Delphi / MSXML:XPath查询失败

时间:2009-10-05 11:00:20

标签: delphi xpath msxml

我已经加载了一个XML文档,现在我希望运行一个XPath查询来选择XML的某个子集。 XML是

<?xml version="1.0"?>
<catalog xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with
      XML.</description>
   </book>
</catalog>

并且程序类似于

procedure RunXPathQuery(XML: IXMLDOMDocument2; Query: string);
begin

  XML.setProperty('SelectionLanguage', 'XPath');

  NodeListResult := XML.documentElement.selectNodes(Query));

  ShowMessage('Found (' + IntToStr(NodeListResult.length) + ') nodes.');

end;

问题是:当我为上面的XML运行XPath查询'/ catalog'时,它返回(如预期的)1个元素的节点列表。但是,如果我从中移除:xsi <catalog xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>并重新运行查询,返回的nodelist为空。如果我删除整个'xmlns'属性,结果节点列表再次有1个元素。

所以我的问题是:我该怎么做才能解决这个问题,即如何让MSXML返回正确数量的实例(运行XPath查询时),无论命名空间(或其他属性)如何?

谢谢!

4 个答案:

答案 0 :(得分:3)

请参阅this link

当您使用<catalog xmlns='http://www.w3.org/2001/XMLSchema-instance'>时,整个节点将被移动到另一个(默认)命名空间。您的XPath不会查看此其他命名空间,因此无法找到任何数据。使用<catalog xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>,您只是将xsi声明为不同的命名空间。这将是与默认命名空间不同的命名空间。

我现在无法测试,但添加like this内容可能有所帮助:

XML.setProperty('SelectionNamespaces', 'xmlns=''http://www.w3.org/2001/XMLSchema-instance''');

或者它可能没有。正如我所说,我现在无法测试它。

答案 1 :(得分:2)

想出来。似乎我的问题已经被描述为herehere(并且很可能也是其他地方的。)

查询/ * [local-name()='catalog']适用于我。

答案 2 :(得分:1)

使用:

document.setProperty('SelectionNamespaces', 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"')

答案 3 :(得分:0)

/*[local-name()='catalog'] 

是您问题的解决方案。 但是为什么要忽略命名空间?引入它们是为了表达某些东西,例如:区分不同类型的目录。通过您的查询,您现在可以选择世界上任何目录的内容,但我认为您只能处理书籍。如果您获得螺丝或汽车目录会发生什么?

前面提到的关于前缀(xsi)的事情是正确的。如果删除前缀,则所有元素都在该命名空间中(然后称为默认命名空间)。但你仍然可以处理它。

在您的代码中,无论如何都要给命名空间一个前缀。它甚至不需要匹配原始前缀:

XML.setProperty('SelectionNamespaces', "xmlns:xyz='http://www.w3.org/2001/XMLSchema-instance'"); 

第二件事是调整XPath查询。那一定是

/xyz:catalog

原始XML仅声明xsi名称空间,但从不使用它。在这种情况下,您可以完全删除它。如果要使用命名空间并且希望它具有前缀,则将XML重写为

<?xml version="1.0"?>
<xsi:catalog xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
  <xsi:book id="bk101">
    <xsi:author>Gambardella, Matthew</xsi:author>
    <xsi:title>XML Developer's Guide</xsi:title>
    <xsi:genre>Computer</xsi:genre>
    <xsi:price>44.95</xsi:price>
    <xsi:publish_date>2000-10-01</xsi:publish_date>  
    <xsi:description>An in-depth look at creating applications with 
    XML.</xsi:description>
 </xsi:book>
</xsi:catalog>