其他分享
首页 > 其他分享> > c – MSXML选择节点不起作用

c – MSXML选择节点不起作用

作者:互联网

我正在开发一个自动化测试应用程序,目前我正在编写一个函数来比较两个XML文件之间的值,这些文件应该是相同的,但可能不是.以下是我正在尝试处理的XML示例:

<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.**.com/**">
  <subreport name="RBDReport">
    <record rowNumber="1">
      <field name="Time">
        <value>0</value>
      </field>
      <field name="Reliability">
        <value>1.000000</value>
      </field>
      <field name="Unreliability">
        <value>0.000000</value>
      </field>
      <field name="Availability">
        <value> </value>
      </field>
      <field name="Unavailability">
        <value> </value>
      </field>
      <field name="Failure Rate">
        <value>N/A</value>
      </field>
      <field name="Number of Failures">
        <value> </value>
      </field>
      <field name="Total Downtime">
        <value> </value>
      </field>
    </record>

(注意,可能有多个<子报告>元素,在这些元素中,有多个< record>元素.)

我想要的是提取< value>两个文档的标签然后比较它们的值.那部分我知道怎么做.问题在于提取本身.

由于我被困在C中,我正在使用MSXML,并编写了一个包装器,以允许我的应用程序抽象出实际的XML操作,以防我决定更改我的数据格式.

该包装器CSimpleXMLParser加载XML文档并将其“最高记录”设置为XML文档的document元素. (CRecord是一个抽象类,其CXMLRecord是其子类之一,它可以单独或按组访问子记录,还允许访问Record的“值”(对于子元素或属性的值,在CXMLRecord的情况下) .)CXMLRecord包含一个MSXML :: MSXMLDOMNodePtr和一个指向CSimpleXMLParser实例的指针.)包装器还包含返回子项的实用程序函数,CXMLRecord用它来返回子记录.

在我的代码中,我执行以下操作(尝试返回所有< subreport>节点以查看它是否有效):

CSimpleXMLParser parserReportData;
parserReportData.OpenXMLDocument(strPathToXML);
bool bGetChildrenSuccess = parserReportData.GetFirstRecord()->GetChildRecords(listpChildren, _T("subreport"));

这总是返回false. CXMLRecord :: GetChildRecords()的实现基本上是肉

MSXML2::IXMLDOMNodeListPtr pListChildren = m_pParser->SelectNodes(strPath, m_pXMLNode);

if (pListChildren->Getlength() == 0)
{
    return false;
}

for (long l = 0; l < pListChildren->Getlength(); ++l)
{
    listRecords.push_back(new CXMLRecord(pListChildren->Getitem(l), m_pParser));
}

return true;

CSimpleXMLParser :: SelectNodes()是:

MSXML2::IXMLDOMNodeListPtr CSimpleXMLParser::SelectNodes(LPCTSTR strXPathFilter, MSXML2::IXMLDOMNodePtr pXMLNode)
{
    return pXMLNode->selectNodes(_bstr_t(strXPathFilter));
}

运行时,最高记录肯定被设置为< report>元素恰当.我可以用它做各种各样的事情,比如获取它的子节点(通过MSXML接口,而不是通过我的包装器)或它的名称等.我知道我的包装器可以工作,因为我在应用程序的其他地方使用它来解析一个XML配置文件,它完美无瑕.

我想也许我正在做一些错误的XPath查询表达式,但我能想到的每一个排列都没有带来任何快乐.当我尝试处理这个XML文件时,IXMLDOMNodePtr :: SelectNodes()返回的MSXML :: IXMLDOMNodeListPtr总是长度为0.

这真让我抓狂.

解决方法:

我习惯用.NET的XmlDocument对象做这个,但我认为这里的效果是一样的:

如果XML文档包含命名空间 – 甚至是未命名的命名空间 – 那么Xpath查询也必须使用一个命名空间.因此,您必须将命名空间添加到XMLDoument中,您也可以在代码中给出一个名称,并在XPATH查询中包含前缀(xml文档和前缀之间的前缀不同并不重要) xpath,只要名称空间对其进行排序)

因此,当您使用像/ report / subreport / record / field / value这样的XPath时,实际上需要先设置文档的命名空间:

  pXMLDoc->setProperty(_bstr_t("SelectionNamespaces"),
                       _bstr_t("xmlns:r="http://www.**.com/**"));

然后使用/ r:report / r:subreport / r:record / r:field / r:value selectNodes()

标签:c,xpath,msxml,selectnodes
来源: https://codeday.me/bug/20190827/1744233.html