在xslt中创建嵌套循环

时间:2019-02-19 09:25:22

标签: xml xslt-2.0

我有一个XML文件,当在节级别=“ 1”中嵌套节级别=“ 2”时也遇到了问题,并且还希望以下兄弟参数应进入节级别1,但我无法获取它。 / p>

输入XML

<section level="1" counter="yes">
    <section level="2" counter="yes">
        <title>Introduction</title>
    </section>
    <para>Started the campaign with reviewing the top procedures for men.</para>
    <para>Gynecomastia (removal of breast tissue).</para>
    <section level="2" counter="yes">
        <title>Capturing the Wave</title>
    </section>
    <para>Our focus initially was to create robust website content.</para>
    <para>Started the campaign with reviewing the top procedures for men.</para>
    <section level="3" counter="yes">
        <title>Our Approach: Build the Platform</title>
    </section>
    <para>Our criteria included that each service and landing page included at least 600 words</para>
    <para>Our focus initially was to create robust website content.</para>
    <section level="4" counter="yes">
        <title>Capturing the Wave</title>
    </section>
    <para>Our content-first strategy, along with a mobile-responsive design</para>
    <para>Our focus initially was to create robust website content.</para>
</section>

输出XML:-

<section level="1" counter="yes">
    <section level="2" counter="yes">
        <title>Introduction</title>
        <para>Started the campaign with reviewing the top procedures for men.</para>
        <para>Gynecomastia (removal of breast tissue).</para>
    </section>
    <section level="2" counter="yes">
        <title>Capturing the Wave</title>
        <para>Our focus initially was to create robust website content.</para>
        <para>Started the campaign with reviewing the top procedures for men.</para>
        <section level="3" counter="yes">
            <title>Our Approach: Build the Platform</title>
            <para>Our criteria included that each service and landing page included at least 600 words</para>
            <para>Our focus initially was to create robust website content.</para>
            <section level="4" counter="yes">
                <title>Capturing the Wave</title>
                <para>Our content-first strategy, along with a mobile-responsive design</para>
                <para>Our focus initially was to create robust website content.</para>
            </section>
        </section>
    </section>
</section>

和xslt

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="no"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

   <xsl:template match="section[@level = '2']">
        <xsl:element name="section">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="child::*"/>
            <xsl:variable name="prev-level-value" select="."/>
            <xsl:for-each select="following-sibling::*:section[@level = '3']">
                <xsl:variable name="curr-level" select="@level - 1"/>
                <xsl:variable name="curr-level-value" select="preceding-sibling::*:section[@level = $curr-level][1]"/>
                <xsl:apply-templates select="self::*:section[@level = '3'][$curr-level-value = $prev-level-value]" mode="nested"/>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

    <xsl:template match="section[@level = '3']" mode="nested">
        <xsl:element name="section">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="child::*"/>
            <xsl:variable name="prev-level-value" select="."/>
            <xsl:for-each select="following-sibling::*:section[@level = '4']">
                <xsl:variable name="curr-level" select="@level - 1"/>
                <xsl:variable name="curr-level-value" select="preceding-sibling::*:section[@level = $curr-level][1]"/>
                <xsl:apply-templates select="self::*:section[@level = '4'][$curr-level-value = $prev-level-value]" mode="nested"/>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>


    <xsl:template match="section[@level = '4']" mode="nested">
        <xsl:element name="section">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="child::*"/>
            <xsl:variable name="prev-level-value" select="."/>
            <xsl:for-each select="following-sibling::*:section[@level = '5']">
                <xsl:variable name="curr-level" select="@level - 1"/>
                <xsl:variable name="curr-level-value" select="preceding-sibling::*:section[@level = $curr-level][1]"/>
                <xsl:apply-templates select="self::*:section[@level = '5'][$curr-level-value = $prev-level-value]" mode="nested"/>

            </xsl:for-each>
        </xsl:element>
    </xsl:template>

    <xsl:template match="section[@level = '5']" mode="nested">
        <xsl:element name="section">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="child::*"/>
            <xsl:variable name="prev-level-value" select="."/>
            <xsl:for-each select="following-sibling::*:section[@level = '6']">
                <xsl:variable name="curr-level" select="@level - 1"/>
                <xsl:variable name="curr-level-value" select="preceding-sibling::*:section[@level = $curr-level][1]"/>
                <xsl:apply-templates select="self::*:section[@level = '6'][$curr-level-value = $prev-level-value]" mode="nested"/>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

    <xsl:template match="section[@level = '6']" mode="nested">
        <xsl:element name="section">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="child::*"/>
            <xsl:variable name="prev-level-value" select="."/>
            <xsl:for-each select="following-sibling::*:section[@level = '7']">
                <xsl:variable name="curr-level" select="@level - 1"/>
                <xsl:variable name="curr-level-value" select="preceding-sibling::*:section[@level = $curr-level][1]"/>
                <xsl:apply-templates select="self::*:section[@level = '7'][$curr-level-value = $prev-level-value]" mode="nested"/>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

我已经在输入xml中运行XSLT,那么我的输出是:

    <section level="1" counter="yes">
    <section level="2" counter="yes">
      <title>Introduction</title>
   </section>
    <para>Started the campaign with reviewing the top procedures for men.</para>
    <para>Gynecomastia (removal of breast tissue).</para>
    <section level="2" counter="yes">
      <title>Capturing the Wave</title>
      <section level="3" counter="yes">
         <title>Our Approach: Build the Platform</title>
         <section level="4" counter="yes">
            <title>Capturing the Wave</title>
         </section>
      </section>
   </section>
    <para>Our focus initially was to create robust website content.</para>
    <para>Started the campaign with reviewing the top procedures for men.</para>
    <section level="3" counter="yes">
        <title>Our Approach: Build the Platform</title>
    </section>
    <para>Our criteria included that each service and landing page included at least 600 words</para>
    <para>Our focus initially was to create robust website content.</para>
    <section level="4" counter="yes">
        <title>Capturing the Wave</title>
    </section>
    <para>Our content-first strategy, along with a mobile-responsive design</para>
    <para>Our focus initially was to create robust website content.</para>
</section>

1 个答案:

答案 0 :(得分:1)

考虑使用xsl:for-each-group group-starting-with并编写一个处理级别嵌套的递归函数:

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

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:function name="mf:group" as="node()*">
      <xsl:param name="nodes" as="node()*"/>
      <xsl:param name="level" as="xs:integer"/>
      <xsl:for-each-group select="$nodes" group-starting-with="section[@level = $level]">
          <xsl:choose>
              <xsl:when test="self::section[@level = $level]">
                  <xsl:copy>
                      <xsl:apply-templates select="@*, *"/>
                      <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                  </xsl:copy>
              </xsl:when>
              <xsl:otherwise>
                  <xsl:apply-templates select="current-group()"/>
              </xsl:otherwise>
          </xsl:choose>
      </xsl:for-each-group>
  </xsl:function>

  <xsl:template match="section[@level = 1 and @level &lt; section/@level]">
      <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:sequence select="mf:group(*, 2)"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94rmq5W

该示例是XSLT 3(自2017年以来由Saxon 9.8或更高版本以及Altova 2017或更高版本支持),但是对于XSLT 2处理器,当然可以拼写使用的xsl:mode声明:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="2.0">

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

  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:function name="mf:group" as="node()*">
      <xsl:param name="nodes" as="node()*"/>
      <xsl:param name="level" as="xs:integer"/>
      <xsl:for-each-group select="$nodes" group-starting-with="section[@level = $level]">
          <xsl:choose>
              <xsl:when test="self::section[@level = $level]">
                  <xsl:copy>
                      <xsl:apply-templates select="@*, *"/>
                      <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
                  </xsl:copy>
              </xsl:when>
              <xsl:otherwise>
                  <xsl:apply-templates select="current-group()"/>
              </xsl:otherwise>
          </xsl:choose>
      </xsl:for-each-group>
  </xsl:function>

  <xsl:template match="section[@level = 1 and @level &lt; section/@level]">
      <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:sequence select="mf:group(*, 2)"/>
      </xsl:copy>
  </xsl:template> 

</xsl:stylesheet>

http://xsltransform.net/jxWYjW3