为什么文本节点值之间没有空格?

时间:2018-11-30 17:57:42

标签: java xml xpath xquery xpath-1.0

我正在使用Xpath表达式从XML文档中获取文本节点,如下所示:

<company>
    <emp>
        <dept>Acct</dept>
        <salary>1000</salary>
        <proj>
            <under>E01</under>
             <under>E02</under>
        </proj>
        <name>John Doe</name>
        <gender>male</gender>
    </emp>
</company>

我已经编写了以下XPATH表达式以获取文本值:

normalize-space(string(//emp))

它正在提取正确值,输出如下:

Acct1000E01E02John Doemale

注意,来自不同节点的文本节点值之间没有空格。

实际上想要以这种方式获得输出值:

`Acct 1000 E01 E02 John Doe`

我已经使用javax.xml.xpath来解析和构建树,如下所示:

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 Document document = builder.parse(new File("/employees.xml"));

 XPath xpath = XPathFactory.newInstance().newXPath();
 String expression = "normalize-space(string(//emp))";
 String output= (String)xPath.compile(expression).evaluate(document, XPathConstants.STRING);

我在这里使用JAVA SE 10。因此,Xpath版本是1.0

是否有更好的方法来提取文本值? 我对XPath很陌生,因此任何建议都将对您有所帮助。

2 个答案:

答案 0 :(得分:1)

您在这里几乎是严厉的。 选择not运算符是正确的方法。 应该是这样的:

/html/body/company/emp/*[not(self::gender)]

也就是说,除gender节点外,emp的所有子节点。
这里有一个完整的javascript例子:

let xpathExpression = '/html/body/company/emp/*[not(self::gender)]';
let contextNode = window.document;
let xpathResult = document.evaluate(xpathExpression, contextNode, 
                                        null, XPathResult.ANY_TYPE, null);

console.log(xpathResult.iterateNext());
console.log(xpathResult.iterateNext());
console.log(xpathResult.iterateNext());
console.log(xpathResult.iterateNext());

答案 1 :(得分:0)

哦,亲爱的,这很复杂...

首先,您尚未使用XPath版本标记您的问题。通常,不了解XPath版本的人都在使用古老的1.0版本,因此我会做出这样的假设:对不起,如果错了。

在XPath 1.0中,给定节点集并期望字符串的函数使用该节点集中第一个节点的字符串值(按文档顺序获取)。

在您的查询中

normalize-space(string(//emp))

//emp选择一个节点集,该节点集恰好包含一个节点,因此string()采用该节点的字符串值。元素节点的字符串值是其所有后代文本节点的串联。 normalize-space函数删除开头和结尾的空白,并将内部空间标准化为单个空白字符。

您已将XML以缩进形式显示为

<company>
    <emp>
        <dept>Acct</dept>
        <salary>1000</salary>

等,因此可以合理地预期元素之间的空格构成<emp>元素的字符串值的一部分。但是您还没有告诉我们如何解析文档并将其变成节点树。解析器通常提供有关如何执行此操作的多个选项,尤其是有关如何处理元素节点之间的空白的选项。默认情况下,大多数保留空白,除非可能有一个架构或DTD告诉解析器该空白不重要。众所周知,微软的MSXML解析器默认情况下会删除空格,当您使用XML表示叙述性文档时,这会引起相当大的问题,但实际上使使用XML处理此类非文档数据的人的工作更加轻松。

您的解析器出于某种原因(我们无法确定)似乎已删除元素节点之间的空白。没有XPath查询将再次带回它。在构建文档时,可以保留空白。取决于您使用的工具。

您的第二个问题询问有关删除输入中的元素之一的问题。这超出了XPath的范围。 XPath只能从输入中选择节点,而不能以任何方式修改它们。要修改树,您需要XSLT或XQuery。

您用//emp[not(descendant::gender)]解决问题的尝试注定是无望的,因为这只会选择没有名为gender的后代元素的员工。您似乎是在猜测语义,而不是使用规范或教程。