【问题标题】:XML Text Formatting for XSL TransformationXSL 转换的 XML 文本格式
【发布时间】:2011-05-11 16:41:01
【问题描述】:

我希望我的标题能解决这个问题。请考虑以下 XML 块和 XSL 示例块。

<root>
<level_one>
My first line of text on level_one
<level_two>
My only line of text on level_two
</level_two>
My second line of text on level_one
</level_one>
</root>

<xsl:template match="level_one">
<xsl:value-of select="text()"/>
<br/>
<xsl:apply-templates select="level_two"/>
</xsl:template>

<xsl:template match="level_two">
<xsl:value-of select="text()"/>
<br/>
</xsl:template>

就目前而言,执行上述操作时的输出(此处为阅读修改)是

My first line of text on level_one
<br/>
My only line of text on level_two
<br/>

我错过了 level_one 上的第二行文字。所以我想知道两件事。

  1. XML 有效吗?据我所知,答案是肯定的,但我错了吗?
  2. 如何修改 XSL 以获得第二行(或者在我的情况下甚至比我显示的更多行)?

谢谢

【问题讨论】:

  • 我认为在文本之间放置子标签不是一个好的xml样式
  • 好问题,+1。请参阅我的答案以了解此问题的原因以及简单自然的解决方案。

标签: xml xslt


【解决方案1】:

使用 xsl:apply-templates 的递归下降的标准 XSLT 处理模型。

<xsl:template match="*">
  <xsl:apply-templates/>
</xsl:template>

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

使用&lt;xsl:value-of select="text()"/&gt; 是个坏消息。在 XSLT 1.0 中,它只显示第一个文本节点(如您所见)。在 XSLT 2.0 中,它显示所有子文本节点,以空格分隔,但这可能不是您想要的,因为它将在第二个句子之前输出第一句和第三句。 (实际上你并没有确切地说出你想要什么输出,所以我不得不猜测。)

【讨论】:

    【解决方案2】:

    即使没有匹配text()的模板,您也可以通过替换输出当前节点(level_one)的两个text()节点子节点:

    <xsl:value-of select="text()"/>
    

    <xsl:copy-of select="text()"/>
    

    在 XSLT 1.0 中,知道&lt;xsl:value-of select="$someNodeSet"/&gt; 仅生成$someNodeSet 节点集的第一个节点(按文档顺序)的字符串值非常重要。

    另一边

    <xsl:copy-of select="$someNodeSet"/>
    

    复制$someNodeSet中包含的所有节点。

    【讨论】:

    • +1 很好地解释了 XSLT 1.0 中 value-of 与 copy-of 的用法。
    【解决方案3】:

    XML 有效吗?据我所知, 答案是肯定的,但我错了吗?

    是的,您的 XML 是有效的。此外,与上面的评论相反,在 XML 中混合内容(文本和元素混合在一起)并没有错。这完全取决于上下文以及 XML 的使用方式。例如,几乎不可能编写没有混合内容的技术手册。 (一个很好的例子是参考元素与段落元素中的文本混合。)

    如何修改 XSL 以便 得到第二行(甚至更多 在我的情况下的行比我显示的要多)?

    我不确定您到底想要完成什么,但您看不到第二行文本的原因是因为您只是将第一行与第一行匹配 &lt;xsl:value-of select="text()"/&gt;

    我不确定这是否适用于您的全套 XML 数据,但您可以将 level_onelevel_two 模板替换为与所有 text() 匹配的模板:

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

    这会产生以下输出:

      My first line of text on level_one
      <br/>
      My only line of text on level_two
      <br/>
      My second line of text on level_one
      <br/>
    

    您还可以通过指定 level_one 和 level_two 父级来缩小匹配范围:

      <xsl:template match="level_one/text()|level_two/text()">
        <xsl:value-of select="."/>
        <br/>
      </xsl:template>
    

    这会产生完全相同的输出,但会保留任何其他文本以在其他模板中进行匹配。

    希望这会有所帮助。

    【讨论】:

    • 是的,它帮了很多忙!我避免使用通用的 text() 模板,以便我可以更好地控制结构和输出。我确实最终使用了通用的 text() 模板,但规定要检查父级,以便它只在我需要的地方生效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-12
    • 2023-03-26
    • 1970-01-01
    • 2016-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多