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

Tho*_*ais 3 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);
Run Code Online (Sandbox Code Playgroud)

部分是空的.

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>
Run Code Online (Sandbox Code Playgroud)

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

为什么XPath不能知道这个默认命名空间?另外,它为什么关心?

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

感谢您的任何见解.

rol*_*lfl 8

JDOM正在做正确的事情.这是一个FAQ,不仅适用于JDOM,也适用于XPath.该XPath规范是对这个(有点)清(我加粗的相关部分):

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

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

您需要为您的默认命名空间"发明"命名空间前缀,并在表达式中使用该前缀(这里我发明了命名空间前缀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/"))
Run Code Online (Sandbox Code Playgroud)