一尘不染

查找XML文档中的所有名称空间声明-xPath 1.0与xPath 2.0

java

作为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文档:

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

阅读 226

收藏
2020-12-03

共1个答案

一尘不染

我认为这将获得所有名称空间,而不会重复:

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 ()
2020-12-03