I have a XML structure where the XML schema is irregular/not formatted. The structure looks like this-
<Host>
<element1>type0</element1>
<element2>Fruits</element2>
....
<elementn>Price0</elementn>
<Menu>
<NodeA>
<element1>type1</element1>
<element2>Fruits</element2>
....
<elementn>Price1</elementn>
<Menu>
<NodeB>
<element1>type2</element1>
<element2>Fruits</element2>
....
<elementn>Price2</elementn>
<Menu>
<NodeC>
<element1>type3</element1>
<element2>Fruits</element2>
....
<elementn>Price3</elementn>
<Menu>
<NodeD>
<Element1>type4</element1>
<Element2>Vegetables</Element2>
....
<Elementn>Price4</elementn>
</NodeD>
</Menu>
</NodeC>
</Menu>
</NodeB>
</Menu>
</NodeA>
<NodeE>
<element1>type5</element1>
<element2>Fruits</element2>
....
<elementn>Price5</elementn>
<Menu>
<NodeF>
<element1>type6</element1>
<element2>Vegetables</element2>
....
<elementn>Price6</elementn>
</NodeF>
</Menu>
</NodeE>
</Menu>
</Host>
Now my expected XML is as follows-
a) if <element2>
== fruits in all the nodes, I need XML schema as follows. I may include or exclude the below n elements right under host -
`<element1>type0</element>
<element2>Fruits</element2>
....
<elementn>Price0</elementn>`
.Expected Result -
<Host>
<NodeA>
<element1>type1</element1>
<element2>Fruits</element2>
....
<elementn>Price1</elementn>
</NodeA>
<NodeB>
<element1>type2</element1>
<element2>Fruits</element2>
....
<elementn>Price2</elementn>
</NodeB>
<NodeC>
<element1>type3</element1>
<element2>Fruits</element2>
....
<elementn>Price3</elementn>
</NodeC>
<NodeE>
<element1>type5</element1>
<element2>Fruits</element2>
....
<elementn>Price5</elementn>
</NodeE>
</Host>
b) if <element2>
== vegetables in all the nodes, I need XML schema as follows
Note: <element2>
== Vegetables is always at the last node in the schema
<Host>
<NodeD>
<element1>type4</element1>
<element2>Vegetables</element2>
....
<elementn>Price4</elementn>
</NodeD>
<NodeF>
<element1>type6</element1>
<element2>Vegetables</element2>
....
<elementn>Price6</elementn>
</NodeF>
</Host>
Any help for getting the above XML formats through XSLT would be a great help.
If you want 2 separate document, you don't actually need 2 XSLTs. You can use one XSLT but with a parameter
<xsl:param name="element2" select="'Fruits'" />
(Here 'Fruits'
is just the default value, should the parameter not be specified by the calling application).
You would start off by selecting the nodes which have element2
equal to the parameter (Do note XML and XSLT is case-sensitive, so element2
is not the same as Element2
in your XML, but I assumed that was a typo in your XML).
<xsl:apply-templates select="//*[element2=$element2]"/>
You would also need a template to ensure when a node is matched, it does not copy the child nodes...
<xsl:template match="*[element2]">
<xsl:copy>
<xsl:apply-templates select="*[not(*)]" />
</xsl:copy>
</xsl:template>
The other nodes would be handled by the identity template.
Try this XSLT...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:param name="element2" select="'Fruits'" />
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="//*[element2=$element2]" mode="copy"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[element2]" mode="copy">
<xsl:copy>
<xsl:apply-templates select="*[not(*)]" mode="copy"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()" mode="copy">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="copy"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that if you were using XSLT 2.0, you could create multiple documents in one call, using xsl:for-each-group
to get the distinct groups, and xsl:result-document
to create a file for each.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/*">
<xsl:for-each-group select="//*[element2]" group-by="element2">
<xsl:result-document href="{current-grouping-key()}.xml" method="xml">
<Host>
<xsl:apply-templates select="current-group()" mode="copy" />
</Host>
</xsl:result-document>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="*[element2]" mode="copy">
<xsl:copy>
<xsl:apply-templates select="*[not(*)]" mode="copy"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()" mode="copy">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="copy" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>