I have a input XML document in which need to move few segments under parent segment with condition <c>
should come under <b>
segment when <b2>
is "8R" only. For other segments <e>
and <f>
there is no condition, just need to move under <d>
.
<?xml version="1.0" encoding="UTF-8"?>
<ns0:TEST_Report xmlns:ns0="urn:abc">
<Record>
<a>
<a1>123</a1>
<a2>11</a2>
</a>
<b>
<b1>23</b1>
<b2>SJ</b2>
</b>
<b>
<b1>67</b1>
<b2>8S</b2>
</b>
<b>
<b1>90</b1>
<b2>8R</b2>
</b>
<c>
<c1>asd</c1>
<c2>2342445435346</c2>
</c>
<c>
<c1>wsx</c1>
<c2>8798987978</c2>
</c>
<d>
<d1>XYZ</d1>
<d2>cvb</d2>
</d>
<e>
<e1>1212</e1>
</e>
<e>
<e1>4321</e1>
</e>
<f>
<f1>11</f1>
<f2>11</f2>
</f>
<f>
<f1>133</f1>
<f2>1133</f2>
</f>
<f>
<f1>1345</f1>
<f2>54434</f2>
</f>
<d>
<d1>XYZ</d1>
<d2>cvb</d2>
</d>
<e>
<e1>1212</e1>
</e>
<f>
<f1>11</f1>
<f2>11</f2>
</f>
<f>
<f1>133</f1>
<f2>1133</f2>
</f>
</Record>
</ns0:TEST_Report>
XSLT code i have tried:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="urn:abc">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TEST_Report">
<ns0:TEST_Report>
<xsl:apply-templates select="@*|node()"/>
</ns0:TEST_Report>
</xsl:template>
<xsl:template match="B">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:apply-templates select="following-sibling::C[1]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="C">
<xsl:if test="preceding-sibling::B[3]">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Required Output:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:TEST_Report xmlns:ns0="urn:abc">
<Record>
<a>
<a1>123</a1>
<a2>11</a2>
</a>
<b>
<b1>23</b1>
<b2>SJ</b2>
</b>
<b>
<b1>67</b1>
<b2>8S</b2>
</b>
<b>
<b1>90</b1>
<b2>8R</b2>
<c>
<c1>asd</c1>
<c2>2342445435346</c2>
</c>
<c>
<c1>wsx</c1>
<c2>8798987978</c2>
</c>
</b>
<d>
<d1>XYZ</d1>
<d2>cvb</d2>
<e>
<e1>1212</e1>
</e>
<e>
<e1>4321</e1>
</e>
<f>
<f1>11</f1>
<f2>11</f2>
</f>
<f>
<f1>133</f1>
<f2>1133</f2>
</f>
<f>
<f1>1345</f1>
<f2>54434</f2>
</f>
</d>
<d>
<d1>XYZ</d1>
<d2>cvb</d2>
<e>
<e1>1212</e1>
</e>
<f>
<f1>11</f1>
<f2>11</f2>
</f>
<f>
<f1>133</f1>
<f2>1133</f2>
</f>
</d>
</Record>
</ns0:TEST_Report>
Kindly help to achieve this using xslt 1.0 code. I have tried few other codes as well but it is not working for this requirement.
This is more complicated than it might seem - not because of the condition on b
, but because you have more than one d
element, each with its own "tail" of e
and f
elements.
From the context of the first d
, all subsequent e
and f
elements are on the following-sibling
axis - regardless of any "intervening" d
elements placed along the way. So basically you are looking for an XSLT 1.0 implementation of group-starting-with
, which could be handled as:
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:key name="c" match="c" use="generate-id(preceding-sibling::b[b2='8R'][1])" />
<xsl:key name="ef" match="e|f" use="generate-id(preceding-sibling::d[1])" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="b[b2='8R']">
<xsl:copy>
<xsl:copy-of select="*"/>
<xsl:copy-of select="key('c', generate-id())"/>
</xsl:copy>
</xsl:template>
<xsl:template match="d">
<xsl:copy>
<xsl:copy-of select="*"/>
<xsl:copy-of select="key('ef', generate-id())"/>
</xsl:copy>
</xsl:template>
<xsl:template match="c[preceding-sibling::b[1]/b2='8R'] | e | f"/>
</xsl:stylesheet>
If every c
has a preceding sibling b
that contains <b2>8R</b2>
, then you can simplify the last template to:
<xsl:template match="c|e|f"/>