1

I have an input xml which has the following structure,

<VEN>
<CUS>
    <MEM>
    <MEM>
    <MEM>
</CUS>
<CUS>
    <MEM>
    <MEM>
    <MEM>
</CUS>

each node occurs multiple times in input xml. There is an attribute @CLM01 in every MEM node which has to be assigned a value depending upon every 20 occurences of MEM nodes. Starting from the first VEN/CUS, if there are 55 nodes of MEM then first 20 nodes will have @CLM01 value of '1' and for same VEN/CUS combination the next 20 nodes will have value '2' and remaining 15 nodes will have @CLM01 value '3'.

And for the next CUS(assuming this CUS has 30 MEM nodes) under the Same VEN the first twenty MEM nodes will have @CLM01 value of '4' and next ten MEM will have @CLM01 with value '5'. This goes on..... I hope i am clear what i am trying to achieve.

Thanks. is it possible? using xslt 1.0

Here is the sample input

<Data>
<VEN vendorId= "v1">
    <CUS custId = "c1">
        <MEM memId="m1" CLM01=""/>
        <MEM memId="m2" CLM01=""/>
        <MEM memId="m3" CLM01=""/>
        <MEM memId="m4" CLM01=""/>
        <MEM memId="m5" CLM01=""/>
    </CUS>
    <CUS custId = "c2">
        <MEM memId="m11" CLM01=""/>
        <MEM memId="m12" CLM01=""/>
        <MEM memId="m13" CLM01=""/>
        <MEM memId="m14" CLM01=""/>
        <MEM memId="m15" CLM01=""/>
        <MEM memId="m16" CLM01=""/>
        <MEM memId="m17" CLM01=""/>
        <MEM memId="m18" CLM01=""/>
    </CUS>
</VEN>
<VEN vendorId= "v2">
    <CUS custId = "c1">
        <MEM memId="m4" CLM01=""/>
        <MEM memId="m5" CLM01=""/>
        <MEM memId="m6" CLM01=""/>
        <MEM memId="m7" CLM01=""/>
        <MEM memId="m8" CLM01=""/>
    </CUS>
    <CUS custId = "c1">
        <MEM memId="m33" CLM01=""/>
        <MEM memId="m44" CLM01=""/>
        <MEM memId="m55" CLM01=""/>
        <MEM memId="m66" CLM01=""/>
        <MEM memId="m77" CLM01=""/>
        <MEM memId="m88" CLM01=""/>
        <MEM memId="m99" CLM01=""/>
        <MEM memId="m11" CLM01=""/>
    </CUS>
</VEN>

The Desired output (instead of 20 occurences of MEM nodes we go for every 3 occurences)

<Data>
<VEN vendorId= "v1">
    <CUS custId = "c1">
        <MEM memId="m1" CLM01="1"/>
        <MEM memId="m2" CLM01="1"/>
        <MEM memId="m3" CLM01="1"/>
        <MEM memId="m4" CLM01="2"/>
        <MEM memId="m5" CLM01="2"/>
    </CUS>
    <CUS custId = "c2">
        <MEM memId="m11" CLM01="3"/>
        <MEM memId="m12" CLM01="3"/>
        <MEM memId="m13" CLM01="3"/>
        <MEM memId="m14" CLM01="4"/>
        <MEM memId="m15" CLM01="4"/>
        <MEM memId="m16" CLM01="4"/>
        <MEM memId="m17" CLM01="5"/>
        <MEM memId="m18" CLM01="5"/>
    </CUS>
</VEN>
<VEN vendorId= "v2">
    <CUS custId = "c1">
        <MEM memId="m4" CLM01="6"/>
        <MEM memId="m5" CLM01="6"/>
        <MEM memId="m6" CLM01="6"/>
        <MEM memId="m7" CLM01="7"/>
        <MEM memId="m8" CLM01="7"/>
    </CUS>
    <CUS custId = "c1">
        <MEM memId="m33" CLM01="8"/>
        <MEM memId="m44" CLM01="8"/>
        <MEM memId="m55" CLM01="8"/>
        <MEM memId="m66" CLM01="9"/>
        <MEM memId="m77" CLM01="9"/>
        <MEM memId="m88" CLM01="9"/>
        <MEM memId="m99" CLM01="10"/>
        <MEM memId="m11" CLM01="10"/>
    </CUS>
</VEN>

3
  • Why don't you provide well-formed input that has the actual structure? And the output you want to produce? Makes it easier for people to figure out what you want to achieve. Commented May 1, 2011 at 21:18
  • @Michael: yes, you are correct. I guess this would help. Thanks. I am using xsl:number storing in variable but i dont know how to achieve condition for incrementing value after every 3 nodes of MEM. Commented May 1, 2011 at 22:18
  • Good question, +1. See my answer for a complete solution. Commented May 2, 2011 at 2:31

2 Answers 2

1

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pSize" select="3"/>


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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <xsl:apply-templates/>
  </xsl:variable>

  <xsl:variable name="vPass2" select=
   "ext:node-set($vrtfPass1)"/>

   <xsl:apply-templates select="$vPass2/*" mode="pass2"/>
 </xsl:template>

 <xsl:template match=
  "MEM[not(following-sibling::MEM)]">
   <xsl:call-template name="identity"/>

   <xsl:variable name="vPos" select=
   "count(preceding-sibling::MEM)+1"/>

   <xsl:variable name="pTimes"
        select="$pSize - ($vPos mod $pSize)"/>

   <xsl:call-template name="genMems">
    <xsl:with-param name="pTimes" select="$pTimes"/>
   </xsl:call-template>
 </xsl:template>

 <xsl:template name="genMems">
  <xsl:param name="pTimes"/>

  <xsl:if test="$pTimes >0">
   <MEM fake="yes"/>

   <xsl:call-template name="genMems">
    <xsl:with-param name="pTimes" select="$pTimes -1"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>

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

 <xsl:template match="MEM/@CLM01" mode="pass2">
  <xsl:attribute name="CLM01">
   <xsl:variable name="vNum">
    <xsl:number count="MEM" level="any"/>
   </xsl:variable>

    <xsl:value-of select=
      "ceiling($vNum div $pSize)"/>
   </xsl:attribute>
  </xsl:template>

  <xsl:template match="MEM[@fake='yes']" mode="pass2"/>
</xsl:stylesheet>

when applied on the provided XML document:

<Data>
    <VEN vendorId= "v1">
        <CUS custId = "c1">
            <MEM memId="m1" CLM01=""/>
            <MEM memId="m2" CLM01=""/>
            <MEM memId="m3" CLM01=""/>
            <MEM memId="m4" CLM01=""/>
            <MEM memId="m5" CLM01=""/>
        </CUS>
        <CUS custId = "c2">
            <MEM memId="m11" CLM01=""/>
            <MEM memId="m12" CLM01=""/>
            <MEM memId="m13" CLM01=""/>
            <MEM memId="m14" CLM01=""/>
            <MEM memId="m15" CLM01=""/>
            <MEM memId="m16" CLM01=""/>
            <MEM memId="m17" CLM01=""/>
            <MEM memId="m18" CLM01=""/>
        </CUS>
    </VEN>
    <VEN vendorId= "v2">
        <CUS custId = "c1">
            <MEM memId="m4" CLM01=""/>
            <MEM memId="m5" CLM01=""/>
            <MEM memId="m6" CLM01=""/>
            <MEM memId="m7" CLM01=""/>
            <MEM memId="m8" CLM01=""/>
        </CUS>
        <CUS custId = "c1">
            <MEM memId="m33" CLM01=""/>
            <MEM memId="m44" CLM01=""/>
            <MEM memId="m55" CLM01=""/>
            <MEM memId="m66" CLM01=""/>
            <MEM memId="m77" CLM01=""/>
            <MEM memId="m88" CLM01=""/>
            <MEM memId="m99" CLM01=""/>
            <MEM memId="m11" CLM01=""/>
        </CUS>
    </VEN>
</Data>

produces the wanted, correct result:

<Data>
   <VEN vendorId="v1">
      <CUS custId="c1">
         <MEM memId="m1" CLM01="1"/>
         <MEM memId="m2" CLM01="1"/>
         <MEM memId="m3" CLM01="1"/>
         <MEM memId="m4" CLM01="2"/>
         <MEM memId="m5" CLM01="2"/>
      </CUS>
      <CUS custId="c2">
         <MEM memId="m11" CLM01="3"/>
         <MEM memId="m12" CLM01="3"/>
         <MEM memId="m13" CLM01="3"/>
         <MEM memId="m14" CLM01="4"/>
         <MEM memId="m15" CLM01="4"/>
         <MEM memId="m16" CLM01="4"/>
         <MEM memId="m17" CLM01="5"/>
         <MEM memId="m18" CLM01="5"/>
      </CUS>
   </VEN>
   <VEN vendorId="v2">
      <CUS custId="c1">
         <MEM memId="m4" CLM01="6"/>
         <MEM memId="m5" CLM01="6"/>
         <MEM memId="m6" CLM01="6"/>
         <MEM memId="m7" CLM01="7"/>
         <MEM memId="m8" CLM01="7"/>
      </CUS>
      <CUS custId="c1">
         <MEM memId="m33" CLM01="8"/>
         <MEM memId="m44" CLM01="8"/>
         <MEM memId="m55" CLM01="8"/>
         <MEM memId="m66" CLM01="9"/>
         <MEM memId="m77" CLM01="9"/>
         <MEM memId="m88" CLM01="9"/>
         <MEM memId="m99" CLM01="10"/>
         <MEM memId="m11" CLM01="10"/>
      </CUS>
   </VEN>
</Data>

Explanation:

  1. Two pass transformation.

  2. The first pass adds fake MEM elements so that each CUS element in the result has MEM children whose number is a multiple of $pSize.

  3. The second pass:

  4. Using and overriding the identity rule.

  5. Using <xsl:number> to get the correct numbering of MEM elements with level="any".

Sign up to request clarification or add additional context in comments.

8 Comments

+1. I'm really educating from each and every one of your posts. Thanks!
But the OP's example implied groups cannot cross <CUS> elements, so the first group in every <CUS> would always have the maximum number of members, provided, of course, that there are enough elements. I've given that some thought, but it appears difficult to solve.
@Michael-Ludwig: Good catch. I hadn't noticed this strange requirement. My answer is now updated to implement this requirement, too.
@Dimitre: <xsl:variable name="vPass2" select="ext:node($vrtfPass1)"/> ----- Unable to perform XSL Transformation. 'Name and Number of arguments do not match any function signature in static context'. Sorry but i have seen this error for first time.
@bluesnowxyz: The xxx:node-set() function is XSLT processor-dependent. What XSLT processor are you using? For MSXML the namespace is: "urn:schemas-microsoft-com:xslt" . I use the EXSLT namespace in my answer, because EXSLT is implemented by the majority of XSLT processors.
|
1

Just for fun, one pass transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pSize" select="3"/>
    <xsl:template match="node()|@*">
        <xsl:param name="pOffset" select="0"/>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pOffset" select="$pOffset"/>
                <xsl:with-param name="pPosition" select="position()"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="VEN|CUS">
        <xsl:param name="pOffset" select="0"/>
        <xsl:variable name="vIsVEN" select="self::VEN"/>
        <xsl:copy>
            <xsl:apply-templates
             select="@*|node()[position()=1 and $vIsVEN or not($vIsVEN)]">
                <xsl:with-param name="pOffset" select="$pOffset"/>
            </xsl:apply-templates>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pOffset"
             select="$pOffset + count(.//MEM[position() mod $pSize = 1])"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="MEM/@CLM01">
        <xsl:param name="pPosition" select="1"/>
        <xsl:param name="pOffset" select="0"/>
        <xsl:attribute name="{name()}">
            <xsl:value-of 
             select="$pOffset + ceiling(($pPosition - 1) div $pSize)"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Output:

<Data>
    <VEN vendorId="v1">
        <CUS custId="c1">
            <MEM memId="m1" CLM01="1"></MEM>
            <MEM memId="m2" CLM01="1"></MEM>
            <MEM memId="m3" CLM01="1"></MEM>
            <MEM memId="m4" CLM01="2"></MEM>
            <MEM memId="m5" CLM01="2"></MEM>
        </CUS>
        <CUS custId="c2">
            <MEM memId="m11" CLM01="3"></MEM>
            <MEM memId="m12" CLM01="3"></MEM>
            <MEM memId="m13" CLM01="3"></MEM>
            <MEM memId="m14" CLM01="4"></MEM>
            <MEM memId="m15" CLM01="4"></MEM>
            <MEM memId="m16" CLM01="4"></MEM>
            <MEM memId="m17" CLM01="5"></MEM>
            <MEM memId="m18" CLM01="5"></MEM>
        </CUS>
    </VEN>
    <VEN vendorId="v2">
        <CUS custId="c1">
            <MEM memId="m4" CLM01="6"></MEM>
            <MEM memId="m5" CLM01="6"></MEM>
            <MEM memId="m6" CLM01="6"></MEM>
            <MEM memId="m7" CLM01="7"></MEM>
            <MEM memId="m8" CLM01="7"></MEM>
        </CUS>
        <CUS custId="c1">
            <MEM memId="m33" CLM01="8"></MEM>
            <MEM memId="m44" CLM01="8"></MEM>
            <MEM memId="m55" CLM01="8"></MEM>
            <MEM memId="m66" CLM01="9"></MEM>
            <MEM memId="m77" CLM01="9"></MEM>
            <MEM memId="m88" CLM01="9"></MEM>
            <MEM memId="m99" CLM01="10"></MEM>
            <MEM memId="m11" CLM01="10"></MEM>
        </CUS>
    </VEN>
    <VEN vendorId="v2">
        <CUS custId="c1">
            <MEM memId="m4" CLM01="1"></MEM>
            <MEM memId="m5" CLM01="1"></MEM>
            <MEM memId="m6" CLM01="1"></MEM>
            <MEM memId="m7" CLM01="2"></MEM>
            <MEM memId="m8" CLM01="2"></MEM>
        </CUS>
        <CUS custId="c1">
            <MEM memId="m33" CLM01="3"></MEM>
            <MEM memId="m44" CLM01="3"></MEM>
            <MEM memId="m55" CLM01="3"></MEM>
            <MEM memId="m66" CLM01="4"></MEM>
            <MEM memId="m77" CLM01="4"></MEM>
            <MEM memId="m88" CLM01="4"></MEM>
            <MEM memId="m99" CLM01="5"></MEM>
            <MEM memId="m11" CLM01="5"></MEM>
        </CUS>
    </VEN>
</Data>

Note: Mixing children and siblings traversal. Tunneling parameters.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.