作为Java 6应用程序的一部分,我想在XML文档中找到所有名称空间声明,包括所有重复项。
编辑 :根据马丁的要求,这是我正在使用的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是否有可能/合理地获得预期的结果?
提示:distinct-values()在xPath 2.0中使用该函数将 不会 返回期望的结果,因为我希望所有名称空间声明,即使同一名称空间被声明两次。例如,考虑以下XML文档:
distinct-values()
<?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
我认为这将获得所有名称空间,而不会重复:
for $i in 1 to count(//namespace::*) return if (empty(index-of((//namespace::*)[position() = (1 to ($i - 1))][name() = name((//namespace::*)[$i])], (//namespace::*)[$i]))) then (//namespace::*)[$i] else ()