尝试将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无法了解此默认命名空间?另外,它为什么关心?
更好的是,我怎么能一般地解决这个问题呢?
感谢您的任何见解。
答案 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/"))