简体   繁体   中英

Limit iteration of inner for-each loop in XSLT

I want to limit the innermost for-each loop (Loop_CLM/CLM) for its parent loop. For example, if innermost will loop more than 2 times, then break and start parent loop and inner from 4th position.

In output, each SUB segment must have max 2 CLM segment, if more then repeat SUB with remaining CLM segment.

I found somewhat similar post xslt - iterate nodes in chunks , but the parent loop has single occurrence.

Attaching the source XML, XSLT, actual output XML and desired output XML.

Modified Source XML:

<OB_X1>
  <Pro>
    <GivenProID>101</GivenProID>
    <LoopSub>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10111</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10112</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10113</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10114</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10111</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10112</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10113</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10114</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1013</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10111</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10112</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1013</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10113</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10114</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
    </LoopSub>
  </Pro>
  <Pro>
    <GivenProID>102</GivenProID>
    <LoopSub>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10111</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10112</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10113</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10114</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10115</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10116</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10111</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10112</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10113</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10114</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLM>
          <CLMID>10115</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
        <CLM>
          <CLMID>10116</CLMID>
          <nextfield1>new1</nextfield1>
          <nextfield2>new2</nextfield2>
        </CLM>
      </LoopCLM>
    </LoopSub>
  </Pro>
</OB_X1>

XSLT:

<?xml version="1.0" encoding="utf-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
                exclude-result-prefixes="msxsl">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
  <xsl:template match="/">
    <xsl:apply-templates select="/Loop_Pro" />
  </xsl:template>
  <xsl:template match="/Loop_Pro">
    <OB_X1>
      <xsl:for-each select="Pro">
        <Pro>
          <GivenProID>
            <xsl:value-of select="ProID" />
          </GivenProID>
          <LoopSub>
            <xsl:for-each select="Loop_Sub/Sub">
              <GivenSubID>
                <xsl:value-of select="SubID" />
              </GivenSubID>
              <LoopCLM>
                <xsl:for-each select="Loop_CLM/CLM">
                  <CLMID>
                    <xsl:value-of select="CLMID" />
                  </CLMID>
                </xsl:for-each>
              </LoopCLM>
            </xsl:for-each>
          </LoopSub>
        </Pro>
      </xsl:for-each>
    </OB_X1>
  </xsl:template>
</xsl:stylesheet>

Output actual XML:

<OB_X1>
  <Pro>
    <GivenProID>101</GivenProID>
    <LoopSub>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <CLMID>10112</CLMID>
        <CLMID>10113</CLMID>
        <CLMID>10114</CLMID>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <CLMID>10112</CLMID>
        <CLMID>10113</CLMID>
        <CLMID>10114</CLMID>
      </LoopCLM>
      <GivenSubID>1013</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <CLMID>10112</CLMID>
        <CLMID>10113</CLMID>
        <CLMID>10114</CLMID>
      </LoopCLM>
    </LoopSub>
  </Pro>
  <Pro>
    <GivenProID>102</GivenProID>
    <LoopSub>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <CLMID>10112</CLMID>
        <CLMID>10113</CLMID>
        <CLMID>10114</CLMID>
        <CLMID>10115</CLMID>
        <CLMID>10116</CLMID>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <CLMID>10112</CLMID>
        <CLMID>10113</CLMID>
        <CLMID>10114</CLMID>
        <CLMID>10115</CLMID>
        <CLMID>10116</CLMID>
      </LoopCLM>
    </LoopSub>
  </Pro>
</OB_X1>

Modified Desired Output XML:

<OB_X1>
  <Pro>
    <GivenProID>101</GivenProID>
    <LoopSub>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
        <CLMID>10112</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
      </LoopCLM>
      <GivenSubID>1011</GivenSubID>
      <LoopCLM>
        <CLMID>10113</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
        <CLMID>10114</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
        <CLMID>10112</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
      </LoopCLM>
      <GivenSubID>1012</GivenSubID>
      <LoopCLM>
        <CLMID>10113</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
        <CLMID>10114</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
      </LoopCLM>
      <GivenSubID>1013</GivenSubID>
      <LoopCLM>
        <CLMID>10111</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
        <CLMID>10112</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
      </LoopCLM>
      <GivenSubID>1013</GivenSubID>
      <LoopCLM>
        <CLMID>10113</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
        <CLMID>10114</CLMID>
        <nextfield1>new1</nextfield1>
        <nextfield2>new2</nextfield2>
      </LoopCLM>
    </LoopSub>
  </Pro>

Appreciate any help !

Thanks, Harish

I hope this would do the job(the breakSize is variable, so you can have any value you want):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:strip-space elements="*"/>
<xsl:variable name="breakSize">2</xsl:variable>
<xsl:template match="/Loop_Pro">
    <OB_X1>
        <xsl:for-each select="Pro">
            <xsl:copy>
                <GivenProID>
                    <xsl:value-of select="ProID"/>
                </GivenProID>
                <xsl:for-each select="Loop_Sub">
                    <LoopSub>
                        <xsl:for-each select="Sub">
                            <xsl:call-template name="LoopCLM">
                                <xsl:with-param name="pos" select="1"/>
                            </xsl:call-template>
                        </xsl:for-each>
                    </LoopSub>
                </xsl:for-each>
            </xsl:copy>
        </xsl:for-each>
    </OB_X1>
</xsl:template>
<xsl:template name="LoopCLM">
    <xsl:param name="pos"/>
    <GivenSubID>
        <xsl:value-of select="SubID"/>
    </GivenSubID>
    <LoopCLM>
        <xsl:copy-of select="Loop_CLM/CLM[position() &lt;= $pos + $breakSize - 1 and position() >= $pos]/CLMID"/>
    </LoopCLM>
    <xsl:if test="Loop_CLM/CLM[position() = $pos + $breakSize]">
        <xsl:call-template name="LoopCLM">
            <xsl:with-param name="pos" select="$pos + $breakSize"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>
</xsl:stylesheet>

Wouldn't this be simpler (and more manageable)?

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="group-size" select="2"/>

<xsl:template match="/Loop_Pro">
    <OB_X1>
        <xsl:apply-templates select="Pro"/>
    </OB_X1>
</xsl:template>

<xsl:template match="Pro">    
    <xsl:copy>
        <GivenProID>
            <xsl:value-of select="ProID"/>
        </GivenProID>
        <xsl:apply-templates select="Loop_Sub"/>
    </xsl:copy>
</xsl:template>     

<xsl:template match="Loop_Sub">     
    <LoopSub>
        <xsl:apply-templates select="Sub"/>
    </LoopSub>
</xsl:template> 

<xsl:template match="Sub"> 
    <xsl:variable name="subID" select="SubID"/>
    <xsl:for-each select="Loop_CLM/CLM[position() mod $group-size = 1]">
        <GivenSubID>
            <xsl:value-of select="$subID"/>
        </GivenSubID>
        <LoopCLM>
            <xsl:copy-of select="(. | following-sibling::CLM[position() &lt; $group-size])/CLMID"/>
        </LoopCLM>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM