I need to transform some XML using XLST 1.0 in Visual Studio 2013.
I have the following XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<MessageTemplates>
<MessageTemplate>
<Segment name="Uno" cardinality="first">
<value>something</value>
</Segment>
<Segment name="Dos" cardinality="second">
<value>something</value>
</Segment>
<Segment name="Tres" cardinality="third">
<value>something</value>
</Segment>
<Segment name="Quatro" cardinality="third">
<value>something</value>
</Segment>
<Segment name="Cinco" cardinality="second">
<value>something</value>
</Segment>
<Segment name="Seis" cardinality="third">
<value>something</value>
</Segment>
<Segment name="Siete" cardinality="first">
<value>something</value>
</Segment>
</MessageTemplate>
</MessageTemplates>
</root>
The cardinality attribute of the Segment node is ordinal, first being the highest, and third being the lowest. I need to create nested levels, based on cardinality, as follows:
<?xml version="1.0" encoding="utf-8"?>
<root>
<MessageTemplates>
<MessageTemplate>
<Cardinality type="first">
<Segment name="Uno">
<value>something</value>
</Segment>
<Cardinality type="second">
<Segment name="Dos">
<value>something</value>
</Segment>
<Cardinality type="third">
<Segment name="Tres">
<value>something</value>
</Segment>
<Segment name="Quatro">
<value>something</value>
</Segment>
</Cardinality>
<Segment name="Cinco">
<value>something</value>
</Segment>
<Cardinality type="third">
<Segment name="Seis">
<value>something</value>
</Segment>
</Cardinality>
</Cardinality>
<Segment name="Siete">
<value>something</value>
</Segment>
</Cardinality>
</MessageTemplate>
</MessageTemplates>
</root>
I have tried several different ways to transform this file, but all have failed. I've searched SO and read dozens of posts, but haven't found any cases that match what I am trying to do. I have also tried searching for incremental ways to accomplish my goal, such as only processing one Segment at a time with recursive template calls, etc. The closest I have come is with the following XSLT:
<xsl:template match="MessageTemplates/MessageTemplate">
<MessageTemplate>
<xsl:copy-of select="@*"/>
<xsl:call-template name="cardinality"/>
</MessageTemplate>
</xsl:template>
<xsl:template name="cardinality" match="MessageTemplates/MessageTemplate/Segment">
<xsl:choose>
<xsl:when test="position() = 1">
<Cardinality type="{Segment/@cardinality}">
<Segment>
<xsl:apply-templates select="@*[name() != 'cardinality'] | node()" />
</Segment>
</Cardinality>
</xsl:when>
<xsl:when test="position() != last() and following-sibling::Segment/@cardinality != @cardinality">
<Cardinality type="{@cardinality}">
<Segment>
<xsl:apply-templates select="@*[name() != 'cardinality'] | node()" />
</Segment>
</Cardinality>
</xsl:when>
<xsl:when test="position() = last()">
<Segment>
<xsl:apply-templates select="@*[name() != 'cardinality'] | node()" />
</Segment>
</xsl:when>
</xsl:choose>
</xsl:template>
Which produced the following XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<Version>1.0</Version>
<MessageTemplates>
<MessageTemplate>
<Cardinality type="first">
<Segment>
<Cardinality type="">
<Segment name="Uno">
<value>something</value>
</Segment>
</Cardinality>
<Cardinality type="second">
<Segment name="Dos">
<value>something</value>
</Segment>
</Cardinality>
<Cardinality type="third">
<Segment name="Tres">
<value>something</value>
</Segment>
</Cardinality>
<Cardinality type="third">
<Segment name="Quatro">
<value>something</value>
</Segment>
</Cardinality>
<Cardinality type="second">
<Segment name="Cinco">
<value>something</value>
</Segment>
</Cardinality>
<Cardinality type="third">
<Segment name="Seis">
<value>something</value>
</Segment>
</Cardinality>
<Segment name="Siete">
<value>something</value>
</Segment>
</Segment>
</Cardinality>
</MessageTemplate>
</MessageTemplates>
</root>
Basically, what I want is to wrap all Segment nodes in a single Cardinality node. Then, if the cardinality value of the next Segment is lower than the cardinality value of the current Segment, I want to wrap all following Segment nodes in a Cardinality node, as long as the cardinality value is the same. I want this to happen for each cardinality level. Finally, I want to move the cardinality value of the Segment to the type attribute of the Cardinality node. The order of the Segment nodes must be maintained.
Any help would be greatly appreciated.
UnoandSietesiblings in the result? They both have the same cardinality of "first".