I need help converting the XML tree structure to text format using XSLT but without altering the sequence of nodes in the XML
Sample XML is as follows
XML:
<File>
<Record>
<FH>
<A>A1</A>
<B>B1</B>
<C>C1</C>
</FH>
<BH>
<a>a1</a>
<b>b1</b>
<c>c1</c>
</BH>
<D>
<d>d1</d>
<e>e1</e>
<f>f1</f>
</D>
<BCR>
<g>g1</g>
<h>h1</h>
<i>i1</i>
</BCR>
<BH>
<a>a2</a>
<b>b2</b>
<c>c2</c>
</BH>
<D>
<d>d2</d>
<e>e2</e>
<f>f2</f>
</D>
<BCR>
<g>g2</g>
<h>h2</h>
<i>i2</i>
</BCR>
<BH>
<a>a3</a>
<b>b3</b>
<c>c3</c>
</BH>
<D>
<d>d3</d>
<e>e3</e>
<f>f3</f>
</D>
<D>
<d>d4</d>
<e>e4</e>
<f>f4</f>
</D>
<D>
<d>d5</d>
<e>e5</e>
<f>f5</f>
</D>
<BCR>
<g>g3</g>
<h>h3</h>
<i>i3</i>
</BCR>
<FCR>
<D>D1</D>
<E>E1</E>
<F>F1</F>
</FCR>
</Record>
</File>
the XSLT I'm using is down below but it's changing the order of the nodes which is not desirable
XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:for-each select="/File/Record/FH">
<xsl:value-of select="A"/>
<xsl:value-of select="B"/>
<xsl:value-of select="C"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:for-each select="/File/Record/BH">
<xsl:value-of select="a"/>
<xsl:value-of select="b"/>
<xsl:value-of select="c"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:for-each select="/File/Record/D">
<xsl:value-of select="d"/>
<xsl:value-of select="e"/>
<xsl:value-of select="f"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:for-each select="/File/Record/BCR">
<xsl:value-of select="g"/>
<xsl:value-of select="h"/>
<xsl:value-of select="i"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:for-each select="/File/Record/FCR">
<xsl:value-of select="D"/>
<xsl:value-of select="E"/>
<xsl:value-of select="F"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
EXPECTED OUTPUT | ACTUAL OUTPUT
A1B1C1 | A1B1C1
a1b1c1 | a1b1c1
d1e1f1 | a2b2c2
g1h1i1 | a3b3c3
a2b2c2 | d1e1f1
d2e2f2 | d2e2f2
g2h2i2 | d3e3f3
a3b3c3 | d4e4f4
d3e3f3 | d5e5f5
d4e4f4 | g1h1i1
d5e5f5 | g2h2i2
g3h3i3 | g3h3i3
D1E1F1 | D1E1F1
Is there any way we can alter the XSLT to preserve the sequence?
Thanks
CodePudding user response:
An XSLT-1.0 approach is the following. Its key feature is applying the templates in document order and not by tag name:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/File/Record">
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="FH">
<xsl:value-of select="A"/>
<xsl:value-of select="B"/>
<xsl:value-of select="C"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="BH">
<xsl:value-of select="a"/>
<xsl:value-of select="b"/>
<xsl:value-of select="c"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="D">
<xsl:value-of select="d"/>
<xsl:value-of select="e"/>
<xsl:value-of select="f"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="BCR">
<xsl:value-of select="g"/>
<xsl:value-of select="h"/>
<xsl:value-of select="i"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="FCR">
<xsl:value-of select="D"/>
<xsl:value-of select="E"/>
<xsl:value-of select="F"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
With XSLT-2.0, you can shorten this code:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/File/Record">
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="FH">
<xsl:value-of select="A,B,C,'
'" separator="" />
</xsl:template>
<xsl:template match="BH">
<xsl:value-of select="a,b,c,'
'" separator="" />
</xsl:template>
<xsl:template match="D">
<xsl:value-of select="d,e,f,'
'" separator="" />
</xsl:template>
<xsl:template match="BCR">
<xsl:value-of select="g,h,i,'
'" separator="" />
</xsl:template>
<xsl:template match="FCR">
<xsl:value-of select="D,E,F,'
'" separator="" />
</xsl:template>
</xsl:stylesheet>
The result should be as desired in both cases.
And if you don't want to output by element name, but rather all children, you could simplify it further:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/File/Record">
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="FH|BH|D|BCR|FCR">
<xsl:value-of select="*,'
'" separator="" />
</xsl:template>
</xsl:stylesheet>