XSLT:仅输出当前节点的文本并规范化空格

3
我有一个以下结构的XML文档。我正在编写一个转换,希望输出节点B中的文本,但忽略元素C和文本节点"title"。基本上,我想提取文本"text goes here"并在新元素中输出它,并使所有空格标准化。有人能帮忙吗?以下是我已经尝试过的内容。
Input Doc
<A>
  <B>
    <C>title</C>
     text goes here
  </B>
</A>

Required output doc
<d>text goes here</d>


Solution A:
<xsl:template match="B">
  <d>       
    <xsl:copy-of select="./text()"/>                
  </d>
</xsl:template>

问题:元素之间的空格会被保留,因此我得到类似于以下内容:
<d>

  Text goes here

</d>

我也尝试在解决方案A的模板中使用value-of语句(<xsl:value-of select="./text()"/>),但是这并没有返回任何文本。这个语句有问题吗?
我应该提到,我已经使用以下代码覆盖了默认的文本处理模板:<xsl:template match="text()" /> 谢谢
3个回答

10

原因是因为 <xsl:value-of select="./text()"/> 返回的是"nothing",是因为 ./text() 返回了当前节点下所有子文本节点组成的节点集合。而一个节点集合的 value-of 是其第一个节点的字符串值,这里指的是在 <B><C> 标签之间的仅包含空格的文本节点。同样地,对于 normalize-space(text()) 也是如此,它将节点集合转换为字符串(第一个节点的值),然后规范化该字符串中的空格。因此,您需要逐个规范化每个子文本节点:

<d>
  <xsl:for-each select="text()">
    <xsl:value-of select="normalize-space(.)"/>
  </xsl:for-each>
</d>

不过需要注意的一点是,如果您输入的内容如下所示:

<A>
  <B>
    <C>title</C>
     text goes here
    <C>subtitle</C>
     more text here
  </B>
</A>

那么您将获得输出

<d>text goes heremore text here</d>

在字幕两侧的位之间没有空格。如果这是一个问题,你可以使用一个诀窍,比如

<d>
  <xsl:for-each select="text()[normalize-space(.)]">
    <xsl:if test="position() &gt; 1"><xsl:text> </xsl:text></xsl:if>
    <xsl:value-of select="normalize-space(.)"/>
  </xsl:for-each>
</d>

迭代仅包含非空格字符的文本节点子元素,并在除第一个之外的所有文本节点前添加空格。

<d>text goes here more text here</d>

0

试试这段代码吧!

我使用了模板覆盖而不是使用<copy-of>

  1. 我将B替换为D..

  2. 我从输出中删除了<C>。这解决了一半的问题,所以<C>节点的文本不会出现在输出中。

  3. 我对所有文本节点应用normalize-space函数..这样多余的空格就会被清除掉 :)

这是代码:

  <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes"/>
      <xsl:template match="B">
        <d>
          <xsl:apply-templates select="node()"/>
        </d>
      </xsl:template>

      <xsl:template match="C"/>

      <xsl:template match="text()">
        <xsl:value-of select="normalize-space(.)"/>
      </xsl:template>
    </xsl:stylesheet>

0

我最接近的方法是使用 child 进行选择: //B/child::text()

child 轴只会返回当前上下文节点的直接子文本节点,因此它将无法匹配 title 节点。


嘿,弗兰克!你能发一下完整的可用代码吗?我尝试使用 B/child::text()value-of select="normalize-space(.)" 以及其他一些组合,但好像对我不起作用。 - Rookie Programmer Aravind
我也无法让它工作。完整的模板会很有帮助。谢谢。 - JimS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接