I need an XSLT transform that copies the whole input document to the output document, inserting elements in a specific order.
Specifically, I want to transform input XML of this general form
<Begin>
<tag1>a</tag1>
<tag2>b</tag2>
<tag3>c</tag3>
<tag4>d</tag4>
<tag5>e</tag5>
</Begin>
to itself, but if the input has no /Begin/tag1
or /Begin/tag4
then I want to provide one in the order given above. That is, I want to transform
<Begin>
<tag2>b</tag2>
<tag3>c</tag3>
<tag5>e</tag5>
</Begin>
to
<Begin>
<tag1>a</tag1>
<tag2>b</tag2>
<tag3>c</tag3>
<tag4>d</tag4>
<tag5>e</tag5>
</Begin>
I asked a related question to this XSLT copy all and replace on conditions with a thought of extrapolating the solution to big number of nodes but I am unable to figure the solution to the above problem.
What you are now asking is doable, but it does not afford quite as tidy a solution as does your previous question. Nevertheless, it is doable.
The approach that seems cleanest to me involves using <xsl:choose>
, which in your previous question you remarked you had not been able to apply as specifically as you wanted. As is usually the case with XSL, the key is to properly select the nodes to which each template applies. You don't want to add default children to every node, but rather only to <Begin>
nodes. You might thus do this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<!-- by default, all nodes and attributes are copied verbatim to the output -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- Begin elements are transformed differently: -->
<xsl:template match="Begin">
<!-- the element itself is copied, along with its attributes, if any -->
<xsl:copy>
<xsl:apply-templates select="@*" />
<!-- each child, tag1 ... tagN, is copied if present or inserted
if absent. A separate choice must be made for each. -->
<xsl:choose>
<xsl:when test="tag1">
<!-- will apply the identity transform, because there is no other
template that matches: -->
<xsl:apply-templates select="tag1" />
</xsl:when>
<xsl:otherwise>
<tag1>x1</tag1>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="tag2">
<xsl:apply-templates select="tag2" />
</xsl:when>
<xsl:otherwise>
<tag2>x2</tag2>
</xsl:otherwise>
</xsl:choose>
<!-- ... the same for tag3, tag4, tag5 ... -->
<!-- no provision is herein made for any child nodes of Begin other than
attributes and child elements tag1 ... tag5 -->
</xsl:copy>
</xsl:template>
</xsl:stylesheet>