问题
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