Reputation: 616
I have the following XML structure:
<Main>
<Node1>Definite</Node1>
<Node2>Definite</Node2>
<Node3>Definite</Node3>
<Node4>Definite</Node4>
<Node5>Definite</Node5>
<Node6>Definite</Node6>
<A>Possible</A>
<B>Possible</B>
<C>Possible</C>
<D>Possible</D>
<E>Possible</E>
<F>Possible</F>
<G>Possible</G>
<H>Possible</H>
<I>Possible</I>
</Main>
The nodes named individual letters eg.<A>
are nodes that may not exist within the XML structure while all other nodes are definite.
I need to insert the node <ZZZ>
within the structure so that it always sits in the position shown below.
<Main>
<Node1>Value</Node1>
<Node2>Value</Node2>
<Node3>Value</Node3>
<Node4>Value</Node4>
<Node5>Value</Node5>
<Node6>Value</Node6>
<A>Value</A>
<B>Value</B>
<C>Value</C>
<D>Value</D>
<E>Value</E>
<ZZZ>Value</ZZZ>
<F>Value</F>
<G>Value</G>
<H>Value</H>
<I>Value</I>
</Main>
So say node <E>
and <C>
and <H>
didnt exist it would be:
<Main>
<Node1>Value</Node1>
<Node2>Value</Node2>
<Node3>Value</Node3>
<Node4>Value</Node4>
<Node5>Value</Node5>
<Node6>Value</Node6>
<A>Value</A>
<B>Value</B>
<D>Value</D>
<ZZZ>Value</ZZZ>
<F>Value</F>
<G>Value</G>
<I>Value</I>
</Main>
Hope this is explained clear enough :)
Upvotes: 1
Views: 126
Reputation: 243479
A more general solution that can be adapted to work with any dynamically specidfied names and any number of definite or possible names:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:occurences>
<definites>
<definite>Node1</definite>
<definite>Node2</definite>
<definite>Node3</definite>
<definite>Node4</definite>
<definite>Node5</definite>
<definite>Node6</definite>
</definites>
<possibles>
<possible>A</possible>
<possible>B</possible>
<possible>C</possible>
<possible>D</possible>
<possible>E</possible>
<possible>F</possible>
<possible>G</possible>
<possible>H</possible>
<possible>I</possible>
</possibles>
</my:occurences>
<xsl:variable name="vOccurencies" select=
"document('')/*/my:occurences"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select=
"*[name() =
($vOccurencies/definites/definite
|
$vOccurencies/possibles/possible
[not(position()
>
string-length(substring-before($vOccurencies/possibles, 'F')))
]
)
]"/>
<ZZZ>Value</ZZZ>
<xsl:apply-templates select=
"*[name()
=
$vOccurencies/possibles/possible
[position()
>
string-length(
substring-before($vOccurencies/possibles, 'F')
)
]
]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<Main>
<Node1>Value</Node1>
<Node2>Value</Node2>
<Node3>Value</Node3>
<Node4>Value</Node4>
<Node5>Value</Node5>
<Node6>Value</Node6>
<A>Value</A>
<B>Value</B>
<C>Value</C>
<D>Value</D>
<E>Value</E>
<ZZZ>Value</ZZZ>
<F>Value</F>
<G>Value</G>
<H>Value</H>
<I>Value</I>
</Main>
the wanted, correct result is produced:
<Main>
<Node1>Value</Node1>
<Node2>Value</Node2>
<Node3>Value</Node3>
<Node4>Value</Node4>
<Node5>Value</Node5>
<Node6>Value</Node6>
<A>Value</A>
<B>Value</B>
<C>Value</C>
<D>Value</D>
<E>Value</E>
<ZZZ>Value</ZZZ>
<F>Value</F>
<G>Value</G>
<H>Value</H>
<I>Value</I>
</Main>
Do Note:
In a realworld situation the my:occurances
element will be in its separate XML document -- thus the XSLT code has no hardcoded element names and needn't be modified when the occurencies xml document is changed.
Upvotes: 0
Reputation: 340
well it is depending on which elements are requiered and which are optional! E.g. if you can say <F> is requierd you can insert the ZZZ-Element before the F-Element:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="F">
<ZZZ>Value</ZZZ>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
if you can not say, there is a requiered element, you need to insert in a template for the Main-Element:
<xsl:template match="Main">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="Node1|Node2|Node3|Node4|Node5|Node6|A|B|C|D|E"/>
<ZZZ>Value</ZZZ>
<xsl:apply-templates select="F|G|H|I"/>
</xsl:copy>
</xsl:template>
Upvotes: 2