xml - XSL转换麻烦

标签 xml xslt

我在使用 XSL 样式表转换 XML 时遇到了一些麻烦,其中输出需要具有不遵循 XML 文件中的结构的结构。

简单的例子:

输入:

<p>This is <b>bold text</b>, <i>italic text</i> and normal text</p>

我的问题是输入中的字符格式是嵌套的,并且它们不能嵌套在输出中(没有任何明显格式的文本被认为具有“正常”字符样式,并且必须在输出中如此定义。

有效输出:

<p>
   <c style="normal">This is </c>
   <c style="bold">bold text</c>
   <c style="normal">, </c>
   <c style="italic">italic text</c>
   <c style="normal"> and normal text</c>
</p>

如何做到这一点?

我可以弄清楚如何获得粗体和斜体格式,但不知道如何在从其他格式之一返回后开始新的“正常”格式,因为我无法保存当前状态。请注意,“正常”不一定必须遵循“粗体”或“斜体”,它是粗体或斜体之前处于事件状态的任何格式,所以我真正想要的是记住我当前使用的格式的某种方式,这样我就可以在使用其他一些字符格式后再次定义它。

请注意,以下(明显的)样式无效,因为它包含嵌套格式。我创建这个没有任何问题:

<p>
   <c style="normal">This is
      <c style="bold">bold text</c>
      , 
      <c style="italic">italic text</c>
      and normal text
   </c>
</p>

最佳答案

我会通过不为元素而是为元素内部的文本节点定义模板来解决此问题,使用每个文本节点的祖先来计算出它应该是什么 style:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output indent="yes" />

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

  <!-- direct text nodes under a p become "normal" -->
  <xsl:template match="p/text()">
    <c style="normal"><xsl:value-of select="." /></c>
  </xsl:template>

  <!-- text nodes under both an i and a b become bold-italic -->
  <xsl:template match="b//i/text() | i//b/text()" priority="2">
    <c style="bold-italic"><xsl:value-of select="." /></c>
  </xsl:template>

  <!-- text nodes under a b but not an i become bold -->
  <xsl:template match="b/text()">
    <c style="bold"><xsl:value-of select="." /></c>
  </xsl:template>

  <!-- text nodes under an i but not a b become italic -->
  <xsl:template match="i/text()">
    <c style="italic"><xsl:value-of select="." /></c>
  </xsl:template>

</xsl:stylesheet>

bi元素本身将使用默认的内置模板规则,该规则仅执行<xsl:apply-templates/>(即不专门为此节点输出任何内容,但继续处理子节点)。

或者,您可以为元素定义模板,并在沿着树向下移动时使用参数将“当前状态”从一个模板传递到下一个模板。如果您有 XSLT 2.0,那么这对于 "tunnel" parameters 来说是一个很好的用途:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="xs">
  <xsl:output indent="yes" />

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

  <!-- output text nodes as <c style="current-style">.  The $style parameter
       is a sequence of strings giving the current nested styles, in order.
       Therefore <b><i>some text</i></b> would be bold-italic whereas
       <i><b>some text</b></i> would be italic-bold. -->
  <xsl:template match="text()">
    <xsl:param tunnel="yes" name="style" as="xs:string*" />
    <!-- use "normal" if no current style -->
    <c style="{if (count($style)) then string-join($style, '-') else 'normal'}">
      <xsl:value-of select="."/>
    </c>
  </xsl:template>

  <xsl:template match="b">
    <xsl:param tunnel="yes" name="style" as="xs:string*" />
    <xsl:apply-templates>
      <xsl:with-param tunnel="yes" name="style" select="($style, 'bold')" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="i">
    <xsl:param tunnel="yes" name="style" as="xs:string*" />
    <xsl:apply-templates>
      <xsl:with-param tunnel="yes" name="style" select="($style, 'italic')" />
    </xsl:apply-templates>
  </xsl:template>

</xsl:stylesheet>

当您使用 $style 时,决定将什么内容作为 apply-templates 参数传递的逻辑可以根据需要而复杂。

如果您仅限于 XSLT 1.0,那么您就没有隧道参数,因此您必须在所有级别上明确显示 paramwith-param 元素,但这应该会让您了解如何继续。

关于xml - XSL转换麻烦,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20799964/

相关文章:

xslt - xsl :variable contains nodeset. 如何输出变量的第n个节点?

xslt - 消除 XSLT 中的重复文件名

xslt - 在哪里可以找到有关 XSLT 文件的优秀教程?

c# - 如果两个变量不相等,则让 Linq 查询返回 null

java - 如何更改 Android Studio 中的第一个 Activity ?

c# - 如何获取 SOAP 元素值

c++ - 使用 Libxml2 的 C++ 程序中的错误

xml - XSLT 忽略多个文件中的重复元素

xml - 如何在 Internet Explorer 中将 xslt 文件中的 document-uri 显示为 html 文档中的文本?

c - libxml2 将节点及其所有内容转换为原始 xml 字符串