【问题标题】:Xerces, xpaths, and XML namespacesXerces、xpath 和 XML 命名空间
【发布时间】:2014-04-19 02:55:18
【问题描述】:

我正在尝试使用 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 深处的某个地方崩溃的地方,我看不清楚,但据我所知,有很多东西看起来已删除或未初始化,所以我不确定是什么正是导致崩溃。

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

【问题讨论】:

    标签: c++ xml xpath namespaces xerces


    【解决方案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();
    

    【讨论】:

      猜你喜欢
      • 2011-08-07
      • 1970-01-01
      • 2011-07-24
      • 1970-01-01
      • 1970-01-01
      • 2013-06-23
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多