Reputation: 27486
I have an incoming XML document that contains some nodes of the form:
<userOptions>
<userOption>
<type>A</type>
<plan>
<frequency>MONTHLY</frequency>
</plan>
<method>
<methodType>X1</methodType>
</method>
</userOption>
<userOption>
<type>B</type>
<plan>
<frequency>QUARTERLY</frequency>
</plan>
<method>
<methodType>X2</methodType>
</method>
</userOption>
<userOption>
<type>A</type>
<plan>
<frequency>3MONTH</frequency>
</plan>
<method>
<methodType>X1-B</methodType>
</method>
</userOption>
</userOptions>
I need to consolidate and transform this into something that looks like this:
<userOptions>
<userOption>
<type>A</type>
<plan>
<frequency>3MONTH</frequency>
<methodType>X1-B</methodType>
</plan>
<plan>
<frequency>MONTHLY</frequency>
<methodType>X1</methodType>
</plan>
<userOption>
<userOption>
<type>B</type>
<plan>
<frequency>QUARTERLY</frequency>
<methodType>X2</methodType>
</plan>
<userOption>
</userOptions>
My current transformation looks like this:
<userOptions>
<xsl:for-each select="//userOptions">
<userOption>
<type>
<xsl:value-of select="type" />
</type>
<xsl:variable name="currentType" select="type"/>
<xsl:message><xsl:value-of select="$currentType"/></xsl:message>
<xsl:variable name="currentMethod" select="method/methodType"/>
<xsl:message><xsl:value-of select="$currentMethod/></xsl:message>
<plan>
<frequency>
<xsl:value-of select="plan/frequency" />
</frequency>
<method>
<xsl:value-of select="method/methodType" />
</method>
</plan>
<xsl:for-each select="../userOptions[type=$currentType and method/methodType!=$currentMethod]">
<plan>
<frequency>
<xsl:value-of select="plan/frequency" />
</frequency>
<method>
<xsl:value-of select="method/methodType" />
</method>
</plan>
</xsl:for-each>
</userOption>
</xsl:for-each>
</userOptions>
The problem is I get duplicates, such as:
<userOption>
<type>A</type>
<plan>
<frequency>3MONTH</frequency>
<methodType>X1-B</methodType>
</plan>
<plan>
<frequency>MONTHLY</frequency>
<methodType>X1</methodType>
</plan>
<userOption>
<userOption>
<type>A</type>
<plan>
<frequency>MONTHLY</frequency>
<methodType>X1</methodType>
</plan>
<plan>
<frequency>3MONTH</frequency>
<methodType>X1-B</methodType>
</plan>
<userOption>
I'm not sure how to consolidate the records with matching type
and different methodType
but also to avoid duplicates.
Upvotes: 0
Views: 115
Reputation: 122364
This is a good candidate for the Muenchian grouping method:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="user-type" match="userOption" use="type" />
<xsl:template match="/">
<userOptions>
<!-- this for-each iterates over a node set consisting of just
the *first* userOption element for each type -->
<xsl:for-each select="userOptions/userOption[count( . | key('user-type', type)[1]) = 1]">
<userOption>
<xsl:copy-of select="type" />
<!-- apply templates for all userOption elements of this type
(including the one we are currently for-eaching over) -->
<xsl:apply-templates select="key('user-type', type)" />
</userOption>
</xsl:for-each>
</userOptions>
</xsl:template>
<xsl:template match="userOption">
<plan>
<frequency>
<xsl:value-of select="plan/frequency" />
</frequency>
<method>
<xsl:value-of select="method/methodType" />
</method>
</plan>
</xsl:template>
</xsl:stylesheet>
This is a nifty way of defining groups of nodes, and then iterating once per group rather than once per node, by careful use of keys. If you can use XSLT 2 there's a much more straightforward method built in to the language (<xsl:for-each-group>
) but that is not available in XSLT 1.
Upvotes: 1