带有XPath的JDOM2不能使用命名空间

时间:2014-07-04 11:28:28

标签: java xml xpath jdom-2

尝试将XPath与具有为根节点声明的默认命名空间的XML文件一起使用。

示例代码:

    final SAXBuilder builder = new SAXBuilder();
    final Document document = builder.build(originalFile);

    final XPathFactory xFactory = XPathFactory.instance();

    final String expression = String.format("//section[@label='%s']/section/section", LABEL);
    final XPathExpression<Element> sectionExpression = xFactory.compile(expression, Filters.element());
    final List<Element> sections = sectionExpression.evaluate(document);

部分为空。

XML的片段

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://www.stellent.com/sitestudio/Project/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.stellent.com/sitestudio/Project/ http://www.stellent.com/sitestudio/ss_project_schema.xsd">
    <section label="Index">
        <section label="xyz">
           <section label="child">
           ...
           </section>
        </section>
    </section>
</project>

删除xmlns="http://www.stellent.com/sitestudio/Project/"有效,但不是解决方案!

为什么XPath无法了解此默认命名空间?另外,它为什么关心?

更好的是,我怎么能一般地解决这个问题呢?

感谢您的任何见解。

1 个答案:

答案 0 :(得分:7)

JDOM正在做正确的事情。这是一个FAQ,不仅适用于JDOM,也适用于XPath。 XPath specification is (somewhat) clear on this (I have bolded the relevant part)

  

使用表达式上下文中的名称空间声明,将节点测试中的QName扩展为扩展名。这与开始和结束标记 中的元素类型名称进行扩展的方式相同,除了使用xmlns声明的默认命名空间 :如果QName没有一个前缀,然后命名空间URI为null(这与扩展属性名称的方式相同)。如果QName具有在表达式上下文中没有名称空间声明的前缀,则会出错。

从XPath的角度来看,这意味着XPath表达式中规则的命名空间处理实际上与XML中的节点不同。对于所有XPath表达式,您需要为表达式定义(复制)名称空间上下文,并且用于表达式的前缀实际上完全独立于实际XML文档中使用的前缀。

你需要发明&#39;默认命名空间的名称空间前缀,并在表达式中使用该前缀(这里我发明了名称空间前缀ns):

final String expression = String.format("//ns:section[@label='%s']/ns:section/ns:section", LABEL);
final XPathExpression<Element> sectionExpression = xFactory.compile(expression, Filters.e, null,
         Namespace.getNamespace("ns", "http://www.stellent.com/sitestudio/Project/"))