【问题标题】:Flattening a deeply nested structure in XSLT在 XSLT 中展平深度嵌套的结构
【发布时间】:2009-12-16 06:56:32
【问题描述】:

我正在尝试学习 XSLT(为了一些假期编码的乐趣)。我想我现在对基础知识(抓取子树、过滤元素和重命名元素)有了很好的理解。我遇到麻烦的地方是彻底重组 XML 结构。如果你有一个嵌套很深的结构并想将它展平,你会怎么做?

例如,假设我正在尝试将 docbook sn-p 转换为 html...

输入(文档):

<section>
  <title>Title A</title>
  <para>foo</para>
  <para>bar</para>
  <section>
    <title>Title B</title>
    <para>baz</para>
    <para>biz</para>
    <section>
      <title>Title C</title>
      <para>bing</para>
    </section>
  </section>
  <section>
    <title>Title D</title>
    <para>fizzle</para>
  </section>
</section>

输出(html):

<h1>Title A</h1>
<p>foo</p>
<p>bar</p>
<h2>Title B</h2>
<p>baz</p>
<p>biz</p>
<h3>Title C</h3>
<p>bing</p>
<h2>Title D</h2>
<p>fizzle</p>

这是xsl:param 和xsl:call-template 发挥作用的地方吗?

谢谢!

【问题讨论】:

标签: xml xslt


【解决方案1】:

Carsten 的测试用例有效(稍作调整,您需要用 / 终止 xsl:value-of),但始终使用 &lt;h2&gt; 作为标题。如果你想根据标题的嵌套级别使用不同的标题元素,那么你还需要一些东西:

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

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

  <xsl:template match="title">
    <xsl:choose>
      <xsl:when test="count(ancestor::section) = 1">
        <h1><xsl:value-of select="." /></h1>
      </xsl:when>
      <xsl:when test="count(ancestor::section) = 2">
        <h2><xsl:value-of select="." /></h2>
      </xsl:when>
      <xsl:otherwise>
        <h3><xsl:value-of select="." /></h3>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="para">
    <p><xsl:value-of select="." /></p>
  </xsl:template>

</xsl:stylesheet>

XPath 函数count(ancestor::section) 将返回作为当前元素父元素的所有&lt;section&gt; 元素的计数。在示例中,我使用了&lt;h1&gt; 和&lt;h2&gt; 用于最外层的两个级别,&lt;h3&gt; 用于更深的嵌套,当然您可以在离题时使用其他差异化。

甚至可以使用以下表达式动态生成航向后的数字:

  <xsl:template match="title">
    <xsl:variable name="heading">h<xsl:value-of select="count(ancestor::section)" /></xsl:variable>
    <xsl:element name="{$heading}">
      <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

其中的xsl:variable 部分创建了一个值为h + 嵌套级别的变量。然后该变量可用作xsl:element 元素的参数,允许您动态定义要创建的元素的名称。

跟进:如果您只想按照建议使用 h1-h6,您可以这样做:

<xsl:template match="title">
  <xsl:variable name="hierarchy" select="count(ancestor::section)"/>
  <xsl:variable name="heading">h<xsl:value-of select="$hierarchy" /></xsl:variable>

  <xsl:choose>
    <xsl:when test="$hierarchy > 6">
      <h6 class="{$heading}"><xsl:value-of select="." /></h6>
    </xsl:when>
    <xsl:otherwise>
      <xsl:element name="{$heading}">
        <xsl:value-of select="." />
      </xsl:element>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

此表达式使用&lt;h6 class="h..."&gt; 表示嵌套深度超过 6 的任何内容。它使用&lt;h1&gt; 到&lt;h6&gt; 表示所有其他层次结构级别。

【讨论】:

  • 太棒了!感谢您的完整课程!
  • 干得好。 :) 我会在第二个模板中添加对 count(ancestor::section) &lt; 7 的检查,以防止创建 &lt;h7&gt; 元素。
【解决方案2】:

这应该做的工作:

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

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

    <xsl:template match="title">
        <h2><xsl:value-of select="." /></h2>
    </xsl:template>

    <xsl:template match="para">
        <p><xsl:value-of select="." /></p>
    </xsl:template>
  </xsl:stylesheet>

对于展平,您不需要调用模板。 如果你使用call-template你交出一些属性,见here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 2022-01-13
    • 2016-05-18
    • 1970-01-01
    • 2019-01-21
    • 2014-05-24
    • 2020-09-23
    相关资源
    最近更新 更多