编辑:根据Martin的要求,这是我正在使用的Java代码:
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
XPathExpression xPathExpression = xPathExpression = xPath.compile("//namespace::*");
NodeList nodeList = (NodeList) xPathExpression.evaluate(xmlDomDocument, XPathConstants.NODESET);
假设我有这个XML文档:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:ele="element.com" xmlns:att="attribute.com" xmlns:txt="textnode.com">
<ele:one>a</ele:one>
<two att:c="d">e</two>
<three>txt:f</three>
</root>
为了找到所有的命名空间声明,我使用 xPath 1.0 将此 xPath 语句应用于 XML 文档:
//namespace::*
它找到了4个命名空间声明,这正是我期望(并希望)的:
/root[1]/@xmlns:att - attribute.com
/root[1]/@xmlns:ele - element.com
/root[1]/@xmlns:txt - textnode.com
/root[1]/@xmlns:xml - http://www.w3.org/XML/1998/namespace
但是,如果我改用xPath 2.0,那么我将得到16个命名空间声明(每个以前的声明都出现了4次),这不是我所期望(或希望)的:
/root[1]/@xmlns:xml - http://www.w3.org/XML/1998/namespace
/root[1]/@xmlns:att - attribute.com
/root[1]/@xmlns:ele - element.com
/root[1]/@xmlns:txt - textnode.com
/root[1]/@xmlns:xml - http://www.w3.org/XML/1998/namespace
/root[1]/@xmlns:att - attribute.com
/root[1]/@xmlns:ele - element.com
/root[1]/@xmlns:txt - textnode.com
/root[1]/@xmlns:xml - http://www.w3.org/XML/1998/namespace
/root[1]/@xmlns:att - attribute.com
/root[1]/@xmlns:ele - element.com
/root[1]/@xmlns:txt - textnode.com
/root[1]/@xmlns:xml - http://www.w3.org/XML/1998/namespace
/root[1]/@xmlns:att - attribute.com
/root[1]/@xmlns:ele - element.com
/root[1]/@xmlns:txt - textnode.com
即使我使用xPath语句的非缩写版本,仍然可以看到这种差异:
/descendant-or-self::node()/namespace::*
并且在oXygen中测试,可以看到它出现在各种XML解析器(LIBXML、MSXML.NET、Saxon)中。(编辑:如我后来在评论中提到的那样,这个说法是不正确的。虽然我认为我正在测试各种XML解析器,但实际上并不是。)
问题1:为什么从xPath 1.0到xPath 2.0有所区别?
问题2:使用xPath 2.0获得所需结果是否可行/合理?
提示:在xPath 2.0中使用distinct-values()
函数无法返回所需结果,因为我想要所有命名空间声明,即使同一个命名空间被声明两次。例如,考虑以下XML文档:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<bar:one xmlns:bar="http://www.bar.com">alpha</bar:one>
<bar:two xmlns:bar="http://www.bar.com">bravo</bar:two>
</root>
所需结果是:
/root[1]/@xmlns:xml - http://www.w3.org/XML/1998/namespace
/root[1]/bar:one[1]/@xmlns:bar - http://www.bar.com
/root[1]/bar:two[1]/@xmlns:bar - http://www.bar.com
<foo xmlns:ns1="http://example.com/ns1"/>
中,foo
元素在XPath/XSLT数据模型中没有属性节点,但在作用域命名空间节点中有两个(一个在标记中,另一个是xml命名空间的内置节点)。 - Martin Honnen//namespace::*
选取了一些命名空间节点,但随后使用的API将结果表示为DOM节点。这种映射可能因实现而异。将XPath映射到DOM时存在其他已知问题,例如对于<foo><![CDATA[text 1]]>text2</foo>
,在DOM中解析时/foo/text()[1]
选择的内容是依赖于实现的,因为foo
元素具有两个子节点,一个CDATA节和一个文本节点,而XPath模型仅有一个文本节点。 - Martin Honnen