【问题标题】:Unwrapping elements with XSLT使用 XSLT 展开元素
【发布时间】:2015-08-07 13:26:50
【问题描述】:

我需要解开(或取消嵌套)一些当前包含在段落标签中的元素(如<p> 标签)。但它们不应该是这样,我需要能够使用 XSLT 来纠正这个问题。

它可能看起来像这样,例如:

<paragraph>Some text here with a <bold>word</bold> in bold, for example, and then an image:
    <image href="whatever.png"></image>
    and possibly some more text here.
</paragraph>

这里我需要将文本(包括内嵌的粗体标签)分隔为一个段落,然后是单独的图像,而不是在段落内部,然后在末尾添加一个新的文本段落。像这样:

<paragraph>Some text here with a <bold>word</bold> in bold, for example, and then an image:</paragraph>
    <image href="whatever.png"></image>
<paragraph>and possibly some more text here.</paragraph>

但我不知道该怎么做。我可以对每个节点都这样做,但是粗体标签也会放在单独的段落中,我不希望这样。

请注意,该标签只是一个示例。列表、表格等也会出现同样的情况。基本上问题是它们在不应该包含在段落标签中时被包装了。因此文本(包括粗体、斜体等内联元素)需要保存为一个块中的段落,但其他类型的元素、图像、表格等需要从中展开,仍然保留正确的当然是内容的顺序。

任何想法表示赞赏!

【问题讨论】:

  • imagelisttable 元素是否始终是 paragraph 元素的直接子元素?或者可以有像&lt;paragraph&gt;This some &lt;bold&gt;bold &lt;image href="foo.png"/&gt;&lt;/bold&gt; text.&lt;/paragraph&gt;这样的进一步嵌套吗?您使用或可以使用哪个版本的 XSLT?

标签: xml xslt


【解决方案1】:

假设您可以使用 XSLT 3.0

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

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="paragraph">
  <xsl:for-each-group select="node()" group-adjacent="boolean(self::image | self::table | self::list)">
    <xsl:choose>
      <xsl:when test="current-grouping-key()">
        <xsl:apply-templates select="current-group()"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy select="..">
          <xsl:apply-templates select="current-group()"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

使用 XSLT 2.0,您可以将 paragraph 的模板更改为

<xsl:template match="paragraph">
  <xsl:for-each-group select="node()" group-adjacent="boolean(self::image | self::table | self::list)">
    <xsl:choose>
      <xsl:when test="current-grouping-key()">
        <xsl:apply-templates select="current-group()"/>
      </xsl:when>
      <xsl:otherwise>
        <paragraph>
          <xsl:apply-templates select="current-group()"/>
        </paragraph>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>

在 XSLT 1.0 中,以下是使用兄弟递归来尝试解决该问题的示例:

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

<xsl:template match="@* | node()" name="identity">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="paragraph">
  <xsl:apply-templates select="node()[1]"/>
</xsl:template>

<xsl:template match="paragraph/image | paragraph/table | paragraph/list">
  <xsl:call-template name="identity"/>
  <xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>

<xsl:template match="paragraph/node()[not(self::image | self::table | self::list)]">
  <paragraph>
    <xsl:call-template name="identity"/>
    <xsl:apply-templates select="following-sibling::node()[1][not(self::image | self::table | self::list)]" mode="copy"/>
  </paragraph>
  <xsl:apply-templates select="following-sibling::node()[self::image | self::table | self::list][1]"/>
</xsl:template>

<xsl:template match="paragraph/node()[not(self::image | self::table | self::list)]" mode="copy">
  <xsl:call-template name="identity"/>
  <xsl:apply-templates select="following-sibling::node()[1][not(self::image | self::table | self::list)]" mode="copy"/>
</xsl:template>  

</xsl:stylesheet>

【讨论】:

  • 很好的答案,谢谢!它在使用 XSLT 2.0 和 Saxon 进行测试时有效。唯一的问题是在这种情况下我很可能不得不使用 XSLT 1.0,我忘了说。有没有可能与 1.0 等效?
  • @AndersSvensson,我添加了一个 XSLT 1.0 示例进行兄弟递归(它以 paragraph/node()[1] 开始,然后沿着以下兄弟轴收集属于一起的节点并直接输出 imagetablelist 元素)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-19
  • 1970-01-01
  • 2021-12-09
  • 1970-01-01
  • 2020-11-03
  • 2013-05-01
相关资源
最近更新 更多