在使用XPath的复杂XML元素中的空白文本节点中选择子文本节点

在使用XPath的复杂XML元素中的空白文本节点中选择子文本节点,xml,xslt,xpath,Xml,Xslt,Xpath,我一直在绞尽脑汁想这个问题,但似乎没有弄对,而且我没有在谷歌上找到正确的关键词 我最近开始使用XSLT和XPath来创建自然语言词汇表的XML描述——这是我的一个项目 问题是,我选择对某些单词使用“混合内容”复杂元素,在某些情况下,我只想获取文本节点 以下是XML文档的一部分: ... <entry category="substantiv"> <word lang="sv">semester</word> <word lang="de">

我一直在绞尽脑汁想这个问题,但似乎没有弄对,而且我没有在谷歌上找到正确的关键词

我最近开始使用XSLT和XPath来创建自然语言词汇表的XML描述——这是我的一个项目

问题是,我选择对某些单词使用“混合内容”复杂元素,在某些情况下,我只想获取文本节点

以下是XML文档的一部分:

...
<entry category="substantiv">
  <word lang="sv">semester</word>
  <word lang="de">
    <article>der</article>Urlaub
    <plural>Urlaube</plural>
  </word>
</entry>
...
我想我要做的是选择word[@lang='de']的所有直接文本节点,然后使用
normalize-space()
删除不必要的空白。但是,如何使用XPath实现这一点?还是有更好的办法?看起来很容易,但我想不出来。顺便说一下,我正试图在XSLT文档中实现这一点

规范化空间(/entry/word[@lang='de']/text()[*])
是我尝试过的事情之一,但这似乎起到了其他作用

/谢谢你的帮助

更新:

以下是XSLT的一部分,根据要求:

...
<xsl:choose>
    <xsl:when test="@category='substantiv'">
        <em><xsl:value-of select="word[@lang='de']/article" /></em>
        <xsl:value-of select="normalize-space(word[@lang='de']/text()[2])" />
        <em>pl. <xsl:value-of select="word[@lang='de']/plural" /></em>
    </xsl:when>
...
。。。
pl。
...
这段代码与格式化的第一个版本配合得很好。为了澄清,我想做的是绘制复杂元素
中文本节点的值,尽管它的格式可能是换行符和空格。我将如何处理该值取决于上下文,但现在我将把它放在一个xhtml文档中

更新2: 我现在使用
,它消除了空文本节点的问题。我还使用:

...
<xsl:choose>
  <xsl:when test="@category='substantiv'">
    <em><xsl:value-of select="word[@lang='de']/article" /></em>
    <xsl:text> </xsl:text>
    <xsl:value-of select="normalize-space(word[@lang='de']/text())" />
    <xsl:text>, </xsl:text>
    <em>pl. <xsl:value-of select="word[@lang='de']/plural" /></em>
  </xsl:when>
...
。。。
, 
pl。
...
但是仍然需要规范化,因为XML中的“Urlaub”后面仍然添加了空格

当我需要到达XSLT文档外部的文本节点“Urlaub”时,我使用:

谢谢大家的帮助

更新3:
尝试改进标题

现在我看到了您的代码,我建议:

<xsl:choose>
  <xsl:when test="@category='substantiv'">
    <em><xsl:value-of select="word[@lang='de']/article" /></em>^
    <!-- select the first non-empty text node and normalize it -->
    <xsl:value-of select="normalize-space(word[@lang='de']/text()[normalize-space() != ''][1])" />
    <em>pl. <xsl:value-of select="word[@lang='de']/plural" /></em>
  </xsl:when>

^
pl。

答案的原始版本

要开始,请执行以下操作:

<entry category="substantiv">
  <word lang="sv">semester</word>
  <word lang="de">
    <article>der</article>Urlaub
    <plural>Urlaube</plural>
  </word>
</entry>

学期
德鲁拉布
乌拉贝
通过此XSLT 1.0时:

<!-- identity template copies everything 1:1, unless other templates apply -->
<xsl:template match="*|@*">
  <xsl:copy>
    <xsl:apply-templates select="*|@*" />
  </xsl:copy>
</xsl:template>

<!-- empty template: ignore every white-space-only text-node child of <word> -->
<xsl:template match="word/text()[normalize-space() = '']" />

将产生以下结果:

<entry category="substantiv">
  <word lang="sv">semester</word>
  <word lang="de"><article>der</article>Urlaub<plural>Urlaube</plural></word>
</entry>

学期
德鲁劳布劳贝
这个答案只是猜测,可能并不完全是你想要的。你的问题无论如何都需要澄清。并非总是你认为你想要的和你实际想要的一样。

试试:

/entry/word[@lang='de']/child::text()[normalize-space(.) != '']
也就是说,抓取所有子文本节点,但不要抓取那些规范化为空字符串的子文本节点


-Oisin

我认为这是你想要的东西的骨架,减去任何normalize-space(),让东西看起来完全像你想要的那样

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <xsl:apply-templates select=".//word"/>
  </xsl:template>
  <xsl:template match="word">
    <xsl:apply-templates select=".//text()"/>
  </xsl:template>
  <xsl:template match="text()"><xsl:value-of select="."/><xsl:text> </xsl:text></xsl:template>  
</xsl:stylesheet>

关键是
//text()
,它返回上下文节点()下任何嵌套级别的所有子文本节点的连接。

此转换:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:value-of select="/*/entry/word[@lang='de']/text()[1]"/>
 </xsl:template>
</xsl:stylesheet>
准确地生成所需的结果

Urlaub
注意事项:使用
指令从源XML文档中删除所有纯空白文本节点


因此,不需要额外的处理(normalize-space()等)

如果没有相关的XSLT上下文,就无法自信地回答这个问题。请在您的问题中添加您正在努力解决的XSLT代码,以及您的实际意图(即想要的输出)。@Tomalak,我不是在努力解决XSLT问题,只是XPath部分。但我添加了它,以防它可能会提供一些必要的信息。您不必为XSLT而烦恼,这是另外一点展示您的代码是有帮助的,因为XSLT和XPath密切相关,许多问题的解决方案可能与您当前尝试的不同看我改变的答案。是的,你完全正确。XML打开了一个全新的奇妙世界,但有时它会让人非常困惑:)提及
子::
轴是多余的。另外,默认情况下,
normalize-space()
在当前节点上运行,因此无需在
中提及它。键入word[@lang='de']/text()[normalize-space()!=''即可。谢谢啊,是的,我一点也不清楚。我不想改变格式化,只想处理不同的格式化场景。但是你在其他方面帮了我,所以你的回答仍然有用。谢谢!:)@你有没有注意到我的答案的上半部分发生了变化?是的,我注意到了,这种变化起了作用。谢谢你的帮助。虽然我现在有点困惑text()到底应该如何工作,但如果我不能弄清楚,我明天会开始一个新问题。@nimbus:
text()
是,尽管有括号,但不是函数。至少不是你想象的那样。它选择文本节点,就像
foo
选择
元素一样。括号是将它与
文本
分开的一种方式,后者将选择
元素。是的,我被它愚弄了。我今天还发现它被称为节点测试。我还认为它会自动将文本节点连接成一个字符串,就像我在XPath末尾加上:
word[@lang=“de”]
一样。但是,现在我更清楚了。:)这就是我认为
//text()
对。。也许我做错了?如果我使用
(虽然还没有开始使用模板),我什么也得不到。但是如果我在XPath计算器中测试它,它会发现5个可能的文本节点,因为还添加了'der'和'Urlaube'。“关键是
返回所有子文本节点的串联的//text()
”——实际上,这是错误的
//text()
选择所有的文本节点,它返回一组单独的节点,而不是串联的字符串。这是一个真正的nic
<dict>
    <entry category="substantiv">
        <word lang="sv">semester</word>
        <word lang="de">
            <article>der</article>Urlaub
            <plural>Urlaube</plural>
        </word>
    </entry>
</dict>
Urlaub