在XSLT中展平深层嵌套的结构

spl*_*cer 2 xml xslt

我正在尝试学习XSLT(对于一些假期编码乐趣).我想我现在已经非常了解基础知识(抓取子树,过滤掉元素和重命名元素).我遇到麻烦的地方就是彻底重组XML结构.如果你有一个深层嵌套的结构并想要展平它,你会怎么做呢?

例如,假设我正在尝试将docbook片段转换为html ...

输入(docbook):

<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>
Run Code Online (Sandbox Code Playgroud)

输出(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>
Run Code Online (Sandbox Code Playgroud)

这是哪里xsl:param,并xsl:call-template开始发挥作用?

谢谢!

nd.*_*nd. 6

Carsten的测试用例有效(需要进行微调,需要xsl:value-of以/ 结尾),但始终<h2>用作标题.如果你想根据标题的嵌套级别使用不同的标题元素,那么你还需要一些东西:

<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>
Run Code Online (Sandbox Code Playgroud)

XPath函数count(ancestor::section)将返回所有<section>元素的计数,这些元素是当前元素的父元素.在这个例子中我已经使用<h1><h2>两个最外面的水平,<h3>任何东西更深的嵌套,当然你可以在你disgression使用其他的分化.

甚至可以使用以下表达式在动态标题后生成数字:

  <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>
Run Code Online (Sandbox Code Playgroud)

其中的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>
Run Code Online (Sandbox Code Playgroud)

该表达式使用<h6 class="h...">了任何有嵌套深度大于6,使用<h1>通过<h6>对所有其他层级.