Delphi/MSXML: XPath queries fail

徘徊边缘 提交于 2019-11-28 01:28:50

问题


I've loaded a XML document, and now I wish to run a XPath query to select a certain subset of the XML. The XML is

<?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>

and the procedure goes something like

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

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

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

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

end;

Problem is: when I run the XPath query '/catalog' for the above XML, it returns (as expected) a nodelist of 1 element. However, if I remove :xsi from <catalog xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> and re-run the query, the nodelist returned is empty. If I remove the entire 'xmlns'-attribute, the resulting nodelist has, once again, 1 element.

So my question is this: what can I do to remedy this, i.e. how do I make MSXML return the correct number of instances (when running a XPath query), regardless of the namespace (or other attributes)?

Thanks!


回答1:


See this link!

When you use <catalog xmlns='http://www.w3.org/2001/XMLSchema-instance'> then the whole node will be moved to a different (default) namespace. Your XPath isn't looking inside this other namespace so it can't find any data. With <catalog xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> you're just declaring xsi as a different namespace. This would be a different namespace than the default namespace.

I can't test it right now but adding something like this might help:

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

Or maybe it doesn't. As I said, I can't test it right now.




回答2:


Figured it out. It seems that my problem has been described here and here (and most likely a zillion other places, too).

The query /*[local-name()='catalog'] works for me.




回答3:


Use:

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



回答4:


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

is a solution to your question. But why would you want to ignore namespaces? They have been introduced to express something, e.g. to distinguish different types of catalogs. With your query, you can now select the content of any catalog in the world, but I assume you can only handle books. What will happen if you get a catalog of screws or cars instead?

The mentioned things about the prefix (xsi) is correct. If you remove the prefix, all elements are in that namespace (called default namespace then). But you can still deal with it.

In your code, give the namespace a prefix anyway. It needn't even match the original prefix:

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

The second thing is to adapt the XPath query. It must then be

/xyz:catalog

The original XML only declares the xsi namespace, but never makes use of it. In this case, you can remove it completely. If you want to use the namespace and you want it with prefixes, then rewrite your XML to

<?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>


来源:https://stackoverflow.com/questions/1519416/delphi-msxml-xpath-queries-fail

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!