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

时间:2010-08-09 18:33:29

标签: xml xslt xpath

我一直在绞尽脑汁,但似乎无法做到正确,而且我没有在谷歌上找到正确的关键词..

我最近开始使用XSLT和XPath来创建自然语言词汇表的XML描述 - 用于我的项目。

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

以下是XML文档的一部分:

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

我的文档中有许多入口元素,在这个例子中,我想使用:/entry/word[@lang='de']/text()来获取'Urlaub',因为我的换行符不起作用。我发现实际上有三个文本节点.. .../text()[2]当然会工作..但是,我事先不知道哪里会有换行符,或者有多少行。如果xml的格式如下,我的第一个版本的路径将起作用,但不是第二个:

...
<word lang="de"><article>der</article>Urlaub
  <plural>Urlaube</plural>
</word>
...

我认为我想要做的是选择单词[@ lang ='de']的所有直接文本节点,然后使用normalize-space()删除不必要的空白区域。但是,如何使用XPath执行此操作?或者,还有更好的方法?这似乎很容易,但我无法弄清楚。我正在尝试在XSLT文档中执行此操作。

normalize-space(/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>
...

此代码适用于第一版格式化。为了澄清,我想要做的是绘制复杂元素<word lang="de">中的文本节点的值,尽管它可能使用换行符和空格格式化。我将对该值做什么取决于上下文,但现在我将它放在一个xhtml文档中。

UPDATE2: 我现在使用<xsl:strip-space elements="*"/>,这消除了空文本节点的问题。我也在使用:

...
<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>
...

仍需要规范化,因为在XML中的“Urlaub”之后仍然添加了空格。

当我需要在XSLT文档之外到达文本节点“Urlaub”时,我使用:
<xsl:value-of select="normalize-space(word[@lang='de']/text()[normalize-space() != ''])" />

感谢所有帮助人员!

更新3: 试图改善标题

4 个答案:

答案 0 :(得分:2)

这种转变:

<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>

应用于提供的XML文档(包含在dict顶部元素中):

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

产生完全想要的结果

Urlaub

请注意:使用<xsl:strip-space>指令从源XML文档中删除所有仅限空格的文本节点。

因此,无需额外处理(normalize-space()等)

答案 1 :(得分:0)

现在我看到你的代码了,我推荐这个:

<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>

答案的原始版本

为了帮助您入门:

<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>

这个答案是一个猜测,可能不完全是你所追求的。无论如何,您的问题需要澄清。并不总是你想要你想要的实际想要的东西。

答案 2 :(得分:0)

尝试:

/entry/word[@lang='de']/child::text()[normalize-space(.) != '']

意思是,抓住所有子文本节点,但不抓取那些规范化为空字符串的节点。

-Oisin

答案 3 :(得分:0)

我认为这是你想要的骨架,减去任何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(),它返回上下文节点()下面任何嵌套级别的所有子文本节点的串联。