XSLT templates and recursion

前端 未结 5 1554
孤街浪徒
孤街浪徒 2020-12-29 06:43

Im new to XSLT and am having some problems trying to format an XML document which has recursive nodes.

My XML Code:

Hopefully my XML shows:

  • All
相关标签:
5条回答
  • 2020-12-29 07:02

    I think you can just write the XSL-T to match on <item>. The only way recursion would matter would be if you wanted to retain parent/child relationships. Matching on <item> will be sufficient if your requirement is to map each one to a bullet in an unordered list

    0 讨论(0)
  • 2020-12-29 07:09

    You should be able to do this without writing a loop, if I understand your needs correctly.

    It's generally better to use a more declarative style, in this instance writing a template matching the <items> tag and converting it to a <ul> and another matching <item> converting it to a <li>. An <xsl:apply-templates/> call inside both templates would supply the recursion.

    0 讨论(0)
  • 2020-12-29 07:12

    This is easy. The XSLT processor does all the recursion and the looping for you, all you need to do is to specify templates for nodes you want to handle.

    <xsl:stylesheet 
      version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >
      <!-- <items> with <item> children becomes <ul> -->
      <xsl:template match="items[item]">
        <ul>
          <xsl:apply-templates select="item" />
        </ul>
      </xsl:template>
    
      <!-- <items> without <item> children is not handled -->
      <xsl:template match="items[not(item)]" />
    
      <!-- <item> with @name becomes <li> -->
      <xsl:template match="item[@name]">
        <li>
          <xsl:value-of select ="@name" />
          <xsl:apply-templates select="items" />
        </li>
      </xsl:template>
    
      <!-- <item> without @name becomes <li>, too -->
      <xsl:template match="item[not(@name)]">
        <li>
          <xsl:value-of select ="id" />
          <xsl:apply-templates select="items" />
        </li>
      </xsl:template>
    </xsl:stylesheet>
    

    The <xsl:apply-templates> always is the recursive/iterative step in XSLT. It takes any nodes that fit its select expression and finds templates for them.

    Your job is it to craft an appropriate select expression, supply a template for every node you want to handle and otherwise get out of the way. ;-) Resist the urge to cram everything into one big template or use <xsl:for-each> just because it feels convenient - it is not. Separate templates create more reusable and maintainable, less deeply nested code, and XSLT processors are optimized for template handling, so this might even be the more efficient approach.

    0 讨论(0)
  • 2020-12-29 07:16

    The following stylesheet performs the specified formatting. Note the use of xsl:apply-templates to recurse down the XML tree. See 5.4 Applying Template Rules for more information.

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes"/>
        <xsl:template match="/">
            <xsl:apply-templates select="items"/>
        </xsl:template>
    
        <xsl:template match="items">
            <ul>
                <xsl:apply-templates select="item" />
            </ul>
        </xsl:template>
    
        <xsl:template match="item">
            <li>
                <xsl:choose>
                    <xsl:when test="@name">
                        <xsl:value-of select="@name"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="id"/>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:apply-templates select="items" />
            </li>
        </xsl:template>
    </xsl:stylesheet>
    
    0 讨论(0)
  • 2020-12-29 07:20

    Would something like this be more what you're after?

    <?xml version="1.0" encoding="iso-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="html" indent="yes"/>
    
      <xsl:template match="items" mode="loop">
        <ul>
          <xsl:for-each select="item">
            <li>
              <xsl:value-of select ="@name" />
              <xsl:value-of select="id" />
              <xsl:for-each select="items">
                <xsl:apply-templates select="." mode="loop" />
              </xsl:for-each>
            </li>
          </xsl:for-each>
        </ul>
      </xsl:template>
    
      <xsl:template match="/" name="test">
        <xsl:apply-templates select="/items" mode="loop" />
      </xsl:template>
    </xsl:stylesheet>
    
    0 讨论(0)
提交回复
热议问题