2014-03-14 58 views
1

我想使用xerces-c爲了解析一個相當大量的從StarUML生成的XML文檔來改變一些東西,但是我遇到了問題讓xpath查詢因爲它不斷崩潰。Xerces,xpaths和XML命名空間

爲了簡化事情,我打出了文件的一部分轉化爲測試一個較小的XML文件,它看起來像這樣:

<?xml version="1.0" encoding="utf-8"?> 
<XPD:UNIT xmlns:XPD="http://www.staruml.com" version="1"> 
    <XPD:HEADER> 
    <XPD:SUBUNITS> 
    </XPD:SUBUNITS> 
    </XPD:HEADER> 
    <XPD:BODY> 
    <XPD:OBJ name="Attributes[3]" type="UMLAttribute" guid="onMjrHQ0rUaSkyFAWtLzKwAA"> 
     <XPD:ATTR name="StereotypeName" type="string">ConditionInteraction</XPD:ATTR> 
    </XPD:OBJ> 
    </XPD:BODY> 
</XPD:UNIT> 

所有我想這個例子做的是找到所有的XPD:OBJ元素,其中只有一個。這個問題似乎源於嘗試使用命名空間進行查詢。當我通過一個非常簡單的xpath查詢XPD:OBJ它會崩潰,但如果我只通過OBJ它不會崩潰,但它不會找到XPD:OBJ元素。

我認爲有一些重要的屬性或設置,我在初始化期間缺少我需要設置,但我不知道它可能是什麼。我查瞭解與命名空間有關的解析器的所有屬性,並啓用了我可以的解析器的所有屬性,但它根本沒有幫助,所以我完全陷入了困境。初始化代碼看起來是這樣的,有很多的事情顯然刪除:

const tXercesXMLCh tXMLManager::kDOMImplementationFeatures[] = 
{ 
    static_cast<tXercesXMLCh>('L'), 
    static_cast<tXercesXMLCh>('S'), 
    static_cast<tXercesXMLCh>('\0') 
}; 

// Instantiate the DOM parser. 
fImplementation = static_cast<tXercesDOMImplementationLS *>(tXercesDOMImplementationRegistry::getDOMImplementation(kDOMImplementationFeatures)); 

if (fImplementation != nullptr) 
{ 
    fParser = fImplementation->createLSParser(tXercesDOMImplementationLS::MODE_SYNCHRONOUS, nullptr); 
    fConfig = fParser->getDomConfig(); 

    // Let the validation process do its datatype normalization that is defined in the used schema language. 
    //fConfig->setParameter(tXercesXMLUni::fgDOMDatatypeNormalization, true); 

    // Ignore comments and whitespace so we don't get extra nodes to process that just waste time. 
    fConfig->setParameter(tXercesXMLUni::fgDOMComments, false); 
    fConfig->setParameter(tXercesXMLUni::fgDOMElementContentWhitespace, false); 

    // Setup some properties that look like they might be required to get namespaces to work but doesn't seem to help at all. 
    fConfig->setParameter(tXercesXMLUni::fgXercesUseCachedGrammarInParse, true); 
    fConfig->setParameter(tXercesXMLUni::fgDOMNamespaces, true); 
    fConfig->setParameter(tXercesXMLUni::fgDOMNamespaceDeclarations, true); 

    // Install our custom error handler. 
    fConfig->setParameter(tXercesXMLUni::fgDOMErrorHandler, &fErrorHandler); 
} 

然後後來我解析文檔,找到根節點,然後運行XPath查詢找到我想要的節點。我離開了大頭說,只是告訴你在哪裏,我的情況下運行XPath查詢有一些明顯錯誤有:

tXercesDOMDocument * doc; // Comes from parsing the file. 
tXercesDOMNode * contextNode; // This is the root node retrieved from the document. 
tXercesDOMXPathResult * xPathResult; 

doc->evaluate("XPD:OBJ", contextNode, nullptr, tXercesDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE), xPathResult); 

evaluate()的調用是它崩潰某處深裏面的Xerces,我看不清楚,但從我所看到的有很多東西看起來被刪除或未初始化,所以我不確定究竟是什麼原因導致了崩潰。

那麼在這裏有什麼東西看起來明顯錯誤或缺失,這是使xerces使用XML名稱空間所必需的嗎?

回答

1

解決方案一直在我面前。問題是你需要創建一個解析器並將其傳遞給evaluate()調用,否則它將無法找出任何名稱空間並拋出異常。崩潰似乎是xerces中的一個錯誤,因爲它試圖在無法解析命名空間時拋出異常時崩潰。我必須深入調試xerces代碼才能找到它,這爲我提供瞭解決方案。

因此,要解決這個問題,我改變了呼叫evaluate()稍微創建根節點解析器,現在,它完美的作品:

tXercesDOMDocument * doc; // Comes from parsing the file. 
tXercesDOMNode * contextNode; // This is the root node retrieved from the document. 
tXercesDOMXPathResult * xPathResult; 

// Create the resolver with the root node, which contains the namespace definition. 
tXercesDOMXPathNSResolver * resolver(doc->createNSResolver(contextNode)); 

doc->evaluate("XPD:OBJ", contextNode, resolver, tXercesDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE), xPathResult); 

// Make sure to release the resolver since anything created from a `create___()` 
// function has to be manually released. 
resolver->release();