Xerces,xpaths和XML命名空间

时间:2014-03-14 01:30:04

标签: c++ xml xpath namespaces xerces

我尝试使用xerces-c来解析从StarUML生成的相当大量的XML文档以便更改某些内容,但我遇到了让xpath查询生效的问题,因为它不断崩溃。

为了简化操作,我将部分文件拆分为一个较小的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个元素,其中只有一个元素。问题似乎源于尝试使用命名空间进行查询。当我传递一个非常简单的XPD:OBJ xpath查询时,它会崩溃,但是如果我只通过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内部某处崩溃的地方,我无法清楚地看到它,但从我所看到的内容中有很多东西看起来被删除或未初始化所以我&# 39;我不确定是什么导致了碰撞。

这里有什么东西看起来显然是错误的或缺少使xerces与XML命名空间一起工作所需的吗?

1 个答案:

答案 0 :(得分: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();