0

I am trying to convert a nested XML structure to a Flat XML using for-each in xslt but struggling :( Below is my source and target, so any inputs using XSLT will be very appreciated.

Source XML

<LS>    
<dlu fD="2012-06-07" tD="2012-06-13">
        <ULUI uid="uid-1" fAD="2012-06-11" lAD="2012-06-11">
          <LU license="License1" count="1"/>
        </ULUI>
        <ULUI uid="uid-2" fAD="2012-06-10" lAD="2012-06-10">
          <LU license="License1" count="1"/>
        </ULUI>
        <ULUI uid="uid-3" fAD="2012-06-09" lAD="2012-06-09">
          <LU license="License1" count="1"/>
        </ULUI>
        <ULUI uid="uid-4" fAD="2012-06-07" lAD="2012-06-08">
          <LU license="License3" count="1"/>
          <LU license="License4" count="1"/>
        </ULUI>
        <ULUI uid="uid-5" fAD="2012-06-07" lAD="2012-06-08">
          <LU license="License1" count="1"/>
          <LU license="License5" count="1"/>
        </ULUI>
      </dlu>
      <dlu fD="2012-06-14" tD="2012-06-20">
        <ULUI uid="uid-1" fAD="2012-06-14" lAD="2012-06-14">
          <LU license="License1" count="1"/>
        </ULUI>
        <ULUI uid="uid-2" fAD="2012-06-15" lAD="2012-06-20">
          <LU license="License2" count="1"/>
          <LU license="License4" count="1"/>
        </ULUI>
        <ULUI uid="uid-3" fAD="2012-06-16" lAD="2012-06-19">
          <LU license="License1" count="1"/>
          <LU license="License5" count="1"/>
        </ULUI>
        <ULUI uid="uid-4" fAD="2012-06-17" lAD="2012-06-18">
          <LU license="License1" count="1"/>
          <LU license="License3" count="1"/>
        </ULUI>
        <ULUI uid="uid-5" fAD="2012-06-17" lAD="2012-06-18">
          <LU license="License7" count="1"/>
          <LU license="License9" count="1"/>
        </ULUI>
    </dlu>
</LS>

Target XML

<FDLU>
<LU>
<LD_FR_DT>2012-06-07</LD_FR_DT
<LD_TO_DT>2012-06-13</LD_TO_DT>
<LU_UID>uid-1</LU_UID>  
<LU_FA_DT>2012-06-11</LU_FA_DT>
<LU_LA_DT>2012-06-11</LU_LA_DT>
<LU_LICENSE>License1</LU_LICENSE>
<LU_COUNT>1</LU_COUNT>
</LU>
<LU>
<LD_FR_DT>2012-06-07</LD_FR_DT
<LD_TO_DT>2012-06-13</LD_TO_DT>
<LU_UID>uid-2</LU_UID>  
<LU_FA_DT>2012-06-10</LU_FA_DT>
<LU_LA_DT>2012-06-10</LU_LA_DT>
<LU_LICENSE>License1</LU_LICENSE>
<LU_COUNT>1</LU_COUNT>
</LU>
<LU>
<LD_FR_DT>2012-06-07</LD_FR_DT
<LD_TO_DT>2012-06-13</LD_TO_DT>
<LU_UID>uid-4</LU_UID>  
<LU_FA_DT>2012-06-07</LU_FA_DT>
<LU_LA_DT>2012-06-08</LU_LA_DT>
<LU_LICENSE>License3</LU_LICENSE>
<LU_COUNT>1</LU_COUNT>
</LU>
<LU>
<LD_FR_DT>2012-06-07</LD_FR_DT
<LD_TO_DT>2012-06-13</LD_TO_DT>
<LU_UID>uid-4</LU_UID>  
<LU_FA_DT>2012-06-07</LU_FA_DT>
<LU_LA_DT>2012-06-08</LU_LA_DT>
<LU_LICENSE>License4</LU_LICENSE>
<LU_COUNT>1</LU_COUNT>
</LU>
<LU>
<LD_FR_DT>2012-06-07</LD_FR_DT
<LD_TO_DT>2012-06-13</LD_TO_DT>
<LU_UID>uid-5</LU_UID>  
<LU_FA_DT>2012-06-07</LU_FA_DT>
<LU_LA_DT>2012-06-08</LU_LA_DT>
<LU_LICENSE>License1</LU_LICENSE>
<LU_COUNT>1</LU_COUNT>
</LU>
<LU>
<LD_FR_DT>2012-06-07</LD_FR_DT
<LD_TO_DT>2012-06-13</LD_TO_DT>
<LU_UID>uid-5</LU_UID>  
<LU_FA_DT>2012-06-07</LU_FA_DT>
<LU_LA_DT>2012-06-08</LU_LA_DT>
<LU_LICENSE>License5</LU_LICENSE>
<LU_COUNT>1</LU_COUNT>
</LU>
<LD_FR_DT>2012-06-14</LD_FR_DT
<LD_TO_DT>2012-06-20</LD_TO_DT>
<LU_UID>uid-1</LU_UID>  
<LU_FA_DT>2012-06-14</LU_FA_DT>
<LU_LA_DT>2012-06-14</LU_LA_DT>
<LU_LICENSE>License1</LU_LICENSE>
<LU_COUNT>1</LU_COUNT>
</LU>
.....
</FDLU>

So basically I need a flat row per LU from source, but my ULUI & DLU are also unbounded so they can appear more than once. I am looking for a solution in xslt 1.0 or 2.0 version. I started with for-each LU and then tried to proceed, but I'm not able to handle ULUI and DLU multi occurrence and values for them simply end up in one line.

My effort in progress

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
     <xsl:variable name="srcDoc1" select="bpws:getVariableData('XMLVar')"/>
   <xsl:template match="/">
      <xsl:element name="FDLU" namespace="">
<!--         <xsl:for-each select="$srcDoc1/LS/DLU"> -->
<!--            <xsl:for-each select="/DLU/ULUI"> -->
                <xsl:for-each select="$srcDoc1/LS/DLU/ULUI/LU">
                       <xsl:element name="LD_FR_DT" namespace="">
                            <xsl:value-of select="$srcDoc1/LS/DLU/@fD"/>
                         </xsl:element>
                       <xsl:element name="LD_TO_DT" namespace="">
                            <xsl:value-of select="$srcDoc1/LS/DLU/@tD"/>
                         </xsl:element>
                       <xsl:element name="LU_UID" namespace="">
                            <xsl:value-of select="$srcDoc1/LS/DLU/ULUI/@uid"/>
                         </xsl:element>
                       <xsl:element name="LU_FA_DT" namespace="">
                            <xsl:value-of select="$srcDoc1/LS/DLU/ULUI/@fAD"/>
                         </xsl:element>
                       <xsl:element name="LU_LA_DT" namespace="">
                            <xsl:value-of select="$srcDoc1/LS/DLU/ULUI/@lAD"/>
                         </xsl:element>
                       <xsl:element name="LU_LICENSE" namespace="">
                            <xsl:value-of select="@license"/>
                         </xsl:element>
                       <xsl:element name="LU_COUNT" namespace="">
                            <xsl:value-of select="@count"/>
                         </xsl:element>
                      </xsl:element>
<!--                    </xsl:for-each> -->
<!--              </xsl:for-each> -->
           </xsl:for-each>
        </xsl:element>
     </xsl:template>
  </xsl:stylesheet>
3
  • Why don't you show us what you have so far. Commented Dec 1, 2015 at 20:08
  • Also, is there a root on your XML or is that two XML documents? Commented Dec 1, 2015 at 20:12
  • Sorry, i missed the root, i added that in source XML. It is one single XML. Also added what i have been trying, may be i am in the wrong direction. Thanks Commented Dec 1, 2015 at 20:26

1 Answer 1

2

I assume this is the correct mapping... this can easily be done with applytemplates as well.

Note: Your example XML is a fragment so I wrapped it with an outer element for testing.

<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 method="xml" indent="yes"/>

  <xsl:template match="/">
    <FDUL>
      <xsl:for-each select="//LU">
        <LU>
          <LD_FR_DT>
            <xsl:value-of select="../../@fD"/>
          </LD_FR_DT>
          <LD_TO_DT>
            <xsl:value-of select="../../@tD"/>
          </LD_TO_DT>
          <LU_UID>
            <xsl:value-of select="../@uid"/>
          </LU_UID>
          <LU_FA_DT>
            <xsl:value-of select="../@fAD"/>
          </LU_FA_DT>
          <LU_LA_DT>
            <xsl:value-of select="../@lAD"/>
          </LU_LA_DT>
          <LU_LICENSE>
            <xsl:value-of select="@license"/>
          </LU_LICENSE>
          <LU_COUNT>
            <xsl:value-of select="@count"/>
          </LU_COUNT>
        </LU>
      </xsl:for-each>
    </FDUL>
  </xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

4 Comments

Interesting, so using ../ i can access outer loop elements and it automatically ensures that even if outer element is unbounded, it will generate one full flat structure
The ../ gets the parent element. There can be only one parent and the parent doesn't care how many children there exist. The //LU is the magic part. It will retrieve all LU elements no matter where they are located in the hierarchy.
If you have a different xpath selector that is returning all of elements that you want as your base result ($srcDoc1/LS/DLU/ULUI/LU in your example) you can use the ../ to go to the parent of the current element. If it also possible to use versus position() or ancestor axis functions to dig around but you really don't need anything that complex for what you are trying to do.
Thanks, just using ../ to access elements ensured the result i wanted. Thank you again for a precise input, much appreciated.

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.