I am new to XSLT and XML. I have the following XML. I wanted to group the consecutive child elements.
<Root>
<Child No="1" Month="0" Date="13/08/2014" Payment="100">
<Totals/>
</Child>
<Child No="2" Month="1" Date="13/09/2014" Payment="100">
<Totals/>
</Child>
<Child No="3" Month="2" Date="13/10/2014" Payment="200">
<Totals/>
</Child>
<Child No="4" Month="3" Date="13/11/2014" Payment="300">
<Totals/>
</Child>
<Child No="5" Month="4" Date="13/12/2014" Payment="300">
<Totals/>
</Child>
<Child No="6" Month="5" Date="13/01/2015" Payment="100">
<Totals/>
</Child>
<Child No="7" Month="6" Date="13/01/2015" Payment="100">
<Totals/>
</Child>
<Child No="8" Month="7" Date="13/01/2015" Payment="100">
<Totals/>
</Child>
<Child No="9" Month="8" Date="13/01/2015" Payment="100">
<Totals/>
</Child>
<Child No="10" Month="9" Date="13/01/2015" Payment="100">
<Totals/>
</Child>
</Root>
I need to create a new PP node when Child[n]/Payment <> Child[n-1]/Payment using the XSLT.
And I am expecting the below result,
<PPS>
<PP>
<Ps>
<StartMonth>0</StartMonth>
<EndMonth>1</EndMonth>
<P>
<Amount>100</Amount>
<startP>1</startP>
</P>
<P>
<Amount>100</Amount>
<startP>2</startP>
</P>
</Ps>
</PP>
<PP>
<Ps>
<StartMonth>2</StartMonth>
<EndMonth>2</EndMonth>
<P>
<Amount>200</Amount>
<startP>3</startP>
</P>
</Ps>
</PP>
<PP>
<Ps>
<StartMonth>3</StartMonth>
<EndMonth>4</EndMonth>
<P>
<Amount>300</Amount>
<startP>4</startP>
</P>
<P>
<Amount>300</Amount>
<startP>5</startP>
</P>
</Ps>
</PP>
<PP>
<Ps>
<StartMonth>5</StartMonth>
<EndMonth>9</EndMonth>
<P>
<Amount>100</Amount>
<startP>6</startP>
</P>
<P>
<Amount>100</Amount>
<startP>7</startP>
</P>
<P>
<Amount>100</Amount>
<startP>8</startP>
</P>
<P>
<Amount>100</Amount>
<startP>9</startP>
</P>
<P>
<Amount>100</Amount>
<startP>10</startP>
</P>
</Ps>
</PP>
</PPS>
Here is my sample xslt
<xsl:stylesheet version="1.0" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="x" match="Child" use="#Payment"/>
<xsl:template match="/Root">
<PPS>
<xsl:for-each select="CF">
<xsl:if test="generate-id(.) = generate-id(key('x',#Payment)[1])">
<PP>
<Ps>
<xsl:for-each select="key('x', #Payment)">
<P>
<Amount><xsl:value-of select="format-number(translate(#Payment, ',','.'),'0.00')"/></Amount>
<startP><xsl:value-of select="#Date"/></startP>
</P>
</xsl:for-each>
</Ps>
</PP>
</xsl:if>
</xsl:for-each>
</PPS>
</xsl:template>
</xsl:stylesheet>
This would work:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Root">
<PPS>
<xsl:for-each select="Child">
<xsl:variable name="Payment" select="#Payment"/>
<xsl:if test="not(preceding::*[1][self::Child and #Payment = $Payment])">
<PPS>
<Ps>
<xsl:apply-templates select="current()"/>
<xsl:apply-templates select="following::*[1][self::Child and #Payment = $Payment]">
<xsl:with-param name="Payment" select="$Payment"/>
</xsl:apply-templates>
</Ps>
</PPS>
</xsl:if>
</xsl:for-each>
</PPS>
</xsl:template>
<xsl:template match="Child">
<xsl:param name="Payment"/>
<P>
<Amount>
<xsl:value-of select="#Payment"/>
</Amount>
<startP>
<xsl:value-of select="#No"/>
</startP>
</P>
<xsl:apply-templates select="following::*[1][self::Child and #Payment = $Payment]"/>
</xsl:template>
</xsl:stylesheet>
Related
I have the following 2 xml files,
Mapping.xml
<xml>
<map ordinal="0" reverse="xxx" forward="ThisIsXxx" />
<map ordinal="0" reverse="yyy" forward="ThisIsYyy" />
<map ordinal="0" reverse="zzz" forward="thisIsZzz" />
<map ordinal="0" reverse="xx1" forward="ThisIsXx1Info" />
<map ordinal="0" reverse="yy1" forward="ThisIsYy1Info" />
<map ordinal="0" reverse="zz1" forward="ThisIsZz1Info" />
</xml>
and an input xml file with a series of elements with some of them having a 'name' attribute
second.xml
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<Children>
<child name="xxx">
<info name="xx1">
</info>
</child>
<child name="yyy">
<info name="yy1">
</info>
</child>
<child name="zzz">
<info name="zz1">
</info>
</child>
</Children> <!-- Added by edit -->
</xml>
What I need is if direction is 'forward' then the second.xml files #name to be set to the value from #forward from the Mapping.xml such as the following,
output.xml
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<Children>
<child name="ThisIsXxx">
<info name="ThisIsXx1Info">
</info>
</child>
<child name="ThisIsZzz">
<info name="ThisIsYy1Info">
</info>
</child>
<child name="ThisIsYyy">
<info name="ThisIsZz1Info">
</info>
</child>
</xml>
Xslt file I have is setting all #name="" but not getting any values from the external file..
<?xml version="1.0" encoding="utf-8"?>
<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"/>
<!-- get the mapping db -->
<xsl:variable name="mapDb" select="document('Mapping.xml')" />
<xsl:variable name="mapFwd" select="forward" />
<!-- for all #name find the #mapdb/*/#reverse == #name and set #name=#mapDb/*/forward -->
<xsl:template match="*/#name">
<xsl:choose>
<xsl:when test="$mapFwd='forward'">
<xsl:attribute name="name">
<xsl:value-of select="$mapDb/xml/map[#reverse='{#name}']/#forward"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="name">
<xsl:value-of select="$mapDb/xml/map[#forward='{#name}']/#reverse"/>
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--Copy Everything unchanged-->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I would appreciate some help.
I think you want to use current() e.g. $mapDb/xml/map[#reverse=current()] in your comparisons in the template matching the #name attribute and of course the variable should be initialized with <xsl:variable name="mapFwd" select="'forward'"/>.
I am using the XSLT 1.0 version and I have the below XML to transform,
<Root>
<Child No="1" Month="0" Date="13/08/2014" Payment="100">
<Totals amount="100"/>
</Child>
<Child No="2" Month="1" Date="13/09/2014" Payment="100">
<Totals amount="100"/>
</Child>
<Child No="3" Month="2" Date="13/10/2014" Payment="200">
<Totals amount="200"/>
</Child>
<Child No="4" Month="3" Date="13/11/2014" Payment="300">
<Totals amount="300"/>
</Child>
<Child No="5" Month="4" Date="13/12/2014" Payment="300">
<Totals amount="300"/>
</Child>
<Child No="6" Month="5" Date="13/01/2015" Payment="100">
<Totals amount="100"/>
</Child>
<Child No="7" Month="6" Date="13/01/2015" Payment="100">
<Totals amount="100"/>
</Child>
<Child No="8" Month="7" Date="13/01/2015" Payment="100">
<Totals amount="100"/>
</Child>
<Child No="9" Month="8" Date="13/01/2015" Payment="100">
<Totals amount="100"/>
</Child>
<Child No="10" Month="9" Date="13/01/2015" Payment="100">
<Totals amount="100"/>
</Child>
</Root>
I wanted to transform The XML as
<PPS>
<PP>
<Ps>
<StartMonth>0</StartMonth>
<EndMonth>1</EndMonth>
<P>
<Amount>100</Amount>
<startP>1</startP>
</P>
<P>
<Amount>100</Amount>
<startP>2</startP>
</P>
</Ps>
</PP>
<PP>
<Ps>
<StartMonth>2</StartMonth>
<EndMonth>2</EndMonth>
<P>
<Amount>200</Amount>
<startP>3</startP>
</P>
</Ps>
</PP>
<PP>
<Ps>
<StartMonth>3</StartMonth>
<EndMonth>4</EndMonth>
<P>
<Amount>300</Amount>
<startP>4</startP>
</P>
<P>
<Amount>300</Amount>
<startP>5</startP>
</P>
</Ps>
</PP>
<PP>
<Ps>
<StartMonth>5</StartMonth>
<EndMonth>9</EndMonth>
<P>
<Amount>100</Amount>
<startP>6</startP>
</P>
<P>
<Amount>100</Amount>
<startP>7</startP>
</P>
<P>
<Amount>100</Amount>
<startP>8</startP>
</P>
<P>
<Amount>100</Amount>
<startP>9</startP>
</P>
<P>
<Amount>100</Amount>
<startP>10</startP>
</P>
</Ps>
</PP>
</PPS>
every time I wanted to create a "P" differing from the last Payment.
Here is the pseudo code, create a new PP, when child[n]/Payment <> child[n-1]/Payment.
P.S., I do not want to consider the Totals node even it has some values.
Many Thanks in advance.
You can use the following XSLT. It wouldn't have been so long if it was in XSLT2.0:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Root">
<PPS>
<xsl:for-each select="Child">
<xsl:variable name="Payment" select="#Payment"/>
<xsl:variable name="start-end">
<StartMonth>
<xsl:value-of select="#Month"/>
</StartMonth>
<xsl:choose>
<xsl:when test="following-sibling::*[1][self::Child and #Payment = $Payment]">
<EndMonth>
<xsl:apply-templates select="following-sibling::*[1]" mode="month">
<xsl:with-param name="Payment" select="$Payment"/>
</xsl:apply-templates>
</EndMonth>
</xsl:when>
<xsl:otherwise>
<EndMonth>
<xsl:value-of select="#Month"/>
</EndMonth>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="not(preceding-sibling::*[1][self::Child and #Payment = $Payment])">
<PP>
<Ps>
<xsl:copy-of select="$start-end"/>
<xsl:apply-templates select="current()"/>
<xsl:apply-templates select="following-sibling::*[1][self::Child and #Payment = $Payment]">
<xsl:with-param name="Payment" select="$Payment"/>
</xsl:apply-templates>
</Ps>
</PP>
</xsl:if>
</xsl:for-each>
</PPS>
</xsl:template>
<xsl:template match="Child">
<xsl:param name="Payment"/>
<P>
<Amount>
<xsl:value-of select="#Payment"/>
</Amount>
<startP>
<xsl:value-of select="#No"/>
</startP>
</P>
<xsl:apply-templates select="following-sibling::*[1][self::Child and #Payment = $Payment]">
<xsl:with-param name="Payment" select="$Payment"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Child" mode="month">
<xsl:param name="Payment"/>
<xsl:choose>
<xsl:when test="following-sibling::*[1][self::Child and #Payment = $Payment]">
<xsl:apply-templates select="following-sibling::*[1]" mode="month">
<xsl:with-param name="Payment" select="$Payment"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="#Month"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Source XML:
<?xml version="1.0" encoding="UTF-8"?>
<BigData version="2.1" xmlns="bank.xsd">
<InsideData type="plan" name="testBANK" id="10">
<header>
<log dateTime="2013-07-27T15:52:30"/>
</header>
<object class="BANK" distName="CITY-1/ABC-1/BANK-1" operation="create" timeStamp="2013-07-27T15:48:20"/>
<object class="BranchItemPeriod" distName="CITY-1/ABC-1/BANK-1/Branch-1/BranchItem-1/BranchItemPeriod-1" operation="create" timeStamp="2013-07-27T15:51:25">
<p name="Week">0</p>
<p name="interval">10</p>
</object>
<object class="BranchItemPeriod" distName="CITY-1/ABC-1/BANK-1/Branch-1/BranchItem-2/BranchItemPeriod-2" operation="update" timeStamp="2013-07-27T15:51:25">
<p name="Week">0</p>
<p name="interval">10</p>
</object>
<object class="Branch" distName="CITY-1/ABC-1/BANK-1/Branch-1" operation="create" timeStamp="2013-07-27T15:48:31"/>
<object class="BranchItem" distName="CITY-1/ABC-1/BANK-1/Branch-1/BranchItem-1" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="BranchItem" distName="CITY-1/ABC-1/BANK-1/Branch-1/BranchItem-2" operation="update" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="Sleep" distName="CITY-1/ABC-1/Sleep-1" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="Dance" distName="CITY-1/ABC-1/Dance-5" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
</InsideData>
</BigData>
Transformation XSL :
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:x="bank.xsd" exclude-result-prefixes="x">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="x:object[#class = 'BANK' ]">
</xsl:template>
<xsl:template match="x:object[#class = 'Branch' ]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="distName">
<xsl:value-of select="concat(substring-before( #distName,'BANK-1/' ), substring-after( #distName, 'BANK-1/'))"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="x:object[#class = 'BranchItem' ]">
<xsl:variable name="branchItem" select="."/>
<xsl:choose>
<xsl:when test="$branchItem/#operation='update' and not(contains($branchItem/#distName, 'JOBS_CREATED_USING_NE_LOCAL_UI'))">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">delete</xsl:attribute>
<xsl:attribute name="distName">
<xsl:value-of select="concat(substring-before( #distName,'BANK-1/' ), substring-after( #distName, 'BANK-1/'))"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">create</xsl:attribute>
<xsl:attribute name="distName">
<xsl:value-of select="concat(substring-before( #distName,'BANK-1/' ), substring-after( #distName, 'BANK-1/'))"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="distName">
<xsl:value-of select="concat(substring-before( #distName,'BANK-1/' ), substring-after( #distName, 'BANK-1/'))"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="x:object[#class = 'BranchItemPeriod' ]">
<xsl:variable name="branchPeiod" select="."/>
<xsl:choose>
<xsl:when test="$branchPeiod/#operation='update' and not(contains($branchPeiod/#distName, 'JOBS_CREATED_USING_NE_LOCAL_UI'))">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="operation">create</xsl:attribute>
<xsl:attribute name="distName">
<xsl:value-of select="concat(substring-before( #distName,'BANK-1/' ), substring-after( #distName, 'BANK-1/'))"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="distName">
<xsl:value-of select="concat(substring-before( #distName,'BANK-1/' ), substring-after( #distName, 'BANK-1/'))"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Output XML :
<?xml version="1.0" encoding="UTF-8"?>
<BigData xmlns="bank.xsd" version="2.1">
<InsideData type="plan" name="testBANK" id="10">
<header>
<log dateTime="2013-07-27T15:52:30"/>
</header>
<object class="BranchItemPeriod" distName="CITY-1/ABC-1/Branch-1/BranchItem-1/BranchItemPeriod-1" operation="create" timeStamp="2013-07-27T15:51:25">
<p name="Week">0</p>
<p name="interval">10</p>
</object>
<object class="BranchItemPeriod" distName="CITY-1/ABC-1/Branch-1/BranchItem-2/BranchItemPeriod-2" operation="create" timeStamp="2013-07-27T15:51:25">
<p name="Week">0</p>
<p name="interval">10</p>
</object>
<object class="Branch" distName="CITY-1/ABC-1/Branch-1" operation="create" timeStamp="2013-07-27T15:48:31"/>
<object class="BranchItem" distName="CITY-1/ABC-1/Branch-1/BranchItem-1" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="BranchItem" distName="CITY-1/ABC-1/Branch-1/BranchItem-2" operation="delete" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="BranchItem" distName="CITY-1/ABC-1/Branch-1/BranchItem-2" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="Sleep" distName="CITY-1/ABC-1/Sleep-1" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="Dance" distName="CITY-1/ABC-1/Dance-5" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
</InsideData>
</BigData>
Desired OUTPUT XML:
<?xml version="1.0" encoding="UTF-8"?>
<BigData xmlns="bank.xsd" version="2.1">
<InsideData type="plan" name="testBANK" id="10">
<header>
<log dateTime="2013-07-27T15:52:30"/>
</header>
<object class="Branch" distName="CITY-1/ABC-1/Branch-1" operation="create" timeStamp="2013-07-27T15:48:31"/>
<object class="BranchItem" distName="CITY-1/ABC-1/Branch-1/BranchItem-1" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="BranchItemPeriod" distName="CITY-1/ABC-1/Branch-1/BranchItem-1/BranchItemPeriod-1" operation="create" timeStamp="2013-07-27T15:51:25">
<p name="Week">0</p>
<p name="interval">10</p>
</object>
<object class="BranchItem" distName="CITY-1/ABC-1/Branch-1/BranchItem-2" operation="delete" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="BranchItem" distName="CITY-1/ABC-1/Branch-1/BranchItem-2" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="BranchItemPeriod" distName="CITY-1/ABC-1/Branch-1/BranchItem-2/BranchItemPeriod-2" operation="create" timeStamp="2013-07-27T15:51:25">
<p name="Week">0</p>
<p name="interval">10</p>
</object>
<object class="Sleep" distName="CITY-1/ABC-1/Sleep-1" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
<object class="Dance" distName="CITY-1/ABC-1/Dance-5" operation="create" timeStamp="2013-07-27T15:50:42">
<p name="openDate">2013-07-27</p>
<p name="closeDate">2013-07-29</p>
</object>
</InsideData>
</BigData>
I could achieve most of desired output except for few...
I want the output to be sorted based on distName attribute of object nodes.
I want the sort to happen only to certain child nodes with class names as Branch , BranchItem , BranchItemPeriod.
Here i try for update with delete and create operation, so i want also to maintain the order of delete and create too which i do in present transformation logic or else can it so happen that i sort all first based on above criteria and apply the other transformation logic.
Any suggestion or help is highly appreciated.
I think what you need here is a template that matches the InsideData element, where you can then select the child object elements in the order you require.
You would first start by outputting the non-"object" elements, assuming these always come before the object elements.
<xsl:apply-templates select="#*|node()[not(self::x:object)]"/>
Then you would select the object elements with the class attribute you desire, sorting in the order you require too:
<xsl:apply-templates select="x:object[#class='Branch' or #class='BranchItem' or #class='BranchItemPeriod']">
<xsl:sort select="#distName"/>
</xsl:apply-templates>
Finally, you would output the object elements which have the the class attributes.
<xsl:apply-templates select="x:object[not(#class='Branch' or #class='BranchItem' or #class='BranchItemPeriod')]"/>
Try adding this template to your XSLT to see how you get on:
<xsl:template match="x:InsideData">
<xsl:copy>
<xsl:apply-templates select="#*|node()[not(self::x:object)]"/>
<xsl:apply-templates select="x:object[#class='Branch' or #class='BranchItem' or #class='BranchItemPeriod']">
<xsl:sort select="#distName"/>
</xsl:apply-templates>
<xsl:apply-templates select="x:object[not(#class='Branch' or #class='BranchItem' or #class='BranchItemPeriod')]"/>
</xsl:copy>
</xsl:template>
The header and child elements are the children of parent. Can I keep header and its children as it is and the remaining subchild nodes of child are to be added to a new element?
<parent>
<header>
<left></left>
<right></right>
</header>
<child>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
</child>
<child>
<subchild></subchild>
<subchild></subchild>
</child>
<child>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
</child>
</parent>
Is there any way where I can generate the below output?
<parent>
<header>
<left></left>
<right></right>
</header>
<element>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
<subchild></subchild>
</element>
</parent>
Make a new element and pass remaining all sub childs nodes of child.
This transform will do what you need. It is a basic identity transform with a special case for child elements, which are simply replaced by all their children.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="child">
<xsl:copy-of select="*"/>
</xsl:template>
</xsl:stylesheet>
output
<parent>
<header>
<left/>
<right/>
</header>
<subchild/>
<subchild/>
<subchild/>
<subchild/>
<subchild/>
<subchild/>
<subchild/>
<subchild/>
</parent>
For y our XML file you may use this XSLT schema for get result like you wnat (use HTML for pretty look in browser)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<head>
<title></title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="parent">
<div id="parent">
<header>
<div id="left"><xsl:value-of select="header/left/text()"/></div>
<div id="right"><xsl:value-of select="header/right/text()"/></div>
</header>
<ul id="elements">
<xsl:for-each select="child/subchild">
<li><xsl:value-of select="text()"/></li>
</xsl:for-each>
</ul>
</div>
</xsl:template>
</xsl:stylesheet>
Result looks like this:
Left block
Right Block
Child 1 - Subchild 1
Child 1 - Subchild 2
Child 1 - Subchild 3
Child 2 - Subchild 1
Child 2 - Subchild 2
Child 3 - Subchild 1
Child 3 - Subchild 2
Child 3 - Subchild 3
For complite make result as in you question - use this XSLT code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="parent">
<parent>
<xsl:value-of select="header/node()"/>
<elements>
<xsl:for-each select="child/subchild">
<xsl:value-of select="node()"/>
</xsl:for-each>
</elements>
</parent>
</xsl:template>
</xsl:stylesheet>
XML:
<Grandparent>
<Parent>
<Children id ="1">
<Info>
<Name>
<label name ="chname" />
</Name>
</Info>
</Children>
<Children name ="2">
<Info>
<Name>
<label name="chname" />
</Name>
</Info>
</Children>
<Children id ="3">
<Info>
<Name>
<label name="chname" />
</Name>
</Info>
</Children>
</Parent>
</Grandparent>
XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="label">
<label id="../../../preceding-sibling::Children/#id">
<xsl:apply-templates select="#*|node()"/>
</label>
</xsl:template>
</xsl:stylesheet>
Expected Output:
<Grandparent>
<Parent>
<Children id ="1">
<Info>
<Name>
<label id="1" name ="chname" />
</Name>
</Info>
</Children>
<Children name ="2">
<Info>
<Name>
<label id="2" name="chname" />
</Name>
</Info>
</Children>
<Children id ="3">
<Info>
<Name>
<label id="3" name="chname" />
</Name>
</Info>
</Children>
</Parent>
</Grandparent>
Im adding A attribute id to "label" tag via template. How can I get the attribute "id" from Children node? this is my code
<label id="../../../preceding-sibling::Children/#id">
it doesnt work. Am I missing something here?
thanks in advance :)
If you want to have the results of an Xpath expression as an attribute, you need to use Attribute Value Templates, so you should be writing it as this
<label id="{../../../preceding-sibling::Children/#id}">
The curly braces indicate it is an expression to be evaluated, rather than a string to be output literally.
However, I think the expression is wrong though in this case. You should be actually doing this:
<label id="{../../../#id}">
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="label">
<label id="{../../../#id}">
<xsl:apply-templates select="#*|node()"/>
</label>
</xsl:template>
</xsl:stylesheet>
When applied to your XML, the following is output
<Grandparent>
<Parent>
<Children id="1">
<Info>
<Name>
<label id="1" name="chname"/>
</Name>
</Info>
</Children>
<Children name="2">
<Info>
<Name>
<label id="" name="chname"/>
</Name>
</Info>
</Children>
<Children id="3">
<Info>
<Name>
<label id="3" name="chname"/>
</Name>
</Info>
</Children>
</Parent>
</Grandparent>
You can use an AVT:
<label id="{../../../#id}">