【问题标题】:Why am I getting no spaces between text node values?为什么文本节点值之间没有空格?
【发布时间】:2018-11-30 17:57:41
【问题描述】:

我正在使用 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 很陌生,所以任何建议都会有所帮助。

【问题讨论】:

    标签: java xml xpath xquery xpath-1.0


    【解决方案1】:

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

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

    即emp的所有子节点除了gender节点。
    这里有一个完整的 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());
    

    【讨论】:

    • 谢谢。但这只能满足我的第二个要求。你能建议我如何实现我的第一个要求吗?
    【解决方案2】:

    天哪,这个很复杂……

    首先,您没有使用 XPath 版本标记您的问题。通常不知道 XPath 版本的人使用的是古老的 1.0 版本,所以我会做出这样的假设:如果错了,请见谅。

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

    在您的查询中

    normalize-space(string(//emp))
    

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

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

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

    等,因此可以合理地预期元素之间的空格构成&lt;emp&gt; 元素的字符串值的一部分。但是您还没有告诉我们文档是如何被解析并变成节点树的。解析器通常提供多个选项来说明如何执行此操作,特别是关于如何处理元素节点之间的空白。大多数默认情况下保留空白,除非可能有一个模式或 DTD 告诉解析器空白无关紧要。众所周知,Microsoft 的 MSXML 解析器默认会丢弃空格,这会在您使用 XML 表示叙述性文档时造成相当大的问题,但实际上使使用 XML 处理此类非文档数据的人们的生活更轻松。

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

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

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

    【讨论】:

    • 我现在用 Xpath 版本更新了这个问题,以及我是如何构建树的。由于我对 XPath 和 Xquery 概念的误解,我删除了第二个问题。
    猜你喜欢
    • 1970-01-01
    • 2013-01-01
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 2022-08-21
    • 2022-11-04
    • 2012-05-23
    • 1970-01-01
    相关资源
    最近更新 更多