Adrian
Adrian

Reputation: 2656

XSLT: Combine nodes based on given list

Any idea how to achieve the desidered output with XSLT?

Source XML:

<results>
   <pageFunctionResult>
      <id>46555</id>
      <name>URC 90 S</name>
      <quantity>5+</quantity>
   </pageFunctionResult>
   <pageFunctionResult>
      <id>46556</id>
      <name>URC 90 M</name>
      <quantity>5+</quantity>
   </pageFunctionResult>
   <pageFunctionResult>
      <id>46557</id>
      <name>URC 90 L</name>
      <quantity>10+</quantity>
   </pageFunctionResult>
   <pageFunctionResult>
      <id>96555</id>
      <name>NICE</name>
      <quantity>5+</quantity>
   </pageFunctionResult>
   <pageFunctionResult>
      <id>26555</id>
      <name>NEW L</name>
      <quantity>5+</quantity>
   </pageFunctionResult>
   <pageFunctionResult>
      <id>26552</id>
      <name>NEW XXL</name>
      <quantity>5+</quantity>
   </pageFunctionResult>
</results>

I need somehow combine these elements based which are in the given list (it can be xsl:variable), for example: "URC 90", "NEW".

Let me show you an example output how it should look:

<results>
   <pageFunctionResult>
      <name>URC 90</name>
      <variantname>URC 90 S</variantname>
      <id>46555</id>
      <quantity>5+</quantity>
      <variant id="1">
         <id>46556</id>
         <name>URC 90 M</name>
         <quantity>5+</quantity>
      </variant>
      <variant id="2">
         <id>46557</id>
         <name>URC 90 L</name>
         <quantity>10+</quantity>
      </variant>
   </pageFunctionResult>
   <pageFunctionResult>
      <id>96555</id>
      <name>NICE</name>
      <quantity>5+</quantity>
   </pageFunctionResult>
   <pageFunctionResult>
      <name>NEW</name>
      <variantname>NEW L</variantname>
      <id>46555</id>
      <quantity>5+</quantity>
      <variant id="1">
         <id>26552</id>
         <name>NEW XXL</name>
         <quantity>5+</quantity>
      </variant>
   </pageFunctionResult>   
</results>

In the source XML we have item which is not in the given list: NICE. These nodes should be copied as it is (no need to modify).

What do you think guys, it is possible to achieve this output if we know part of the <name> element?

Upvotes: 0

Views: 76

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167471

Here is an XSLT 2.0 sample which achieves the grouping as you want it:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf">

    <xsl:param name="values" select="'NEW', 'URC 90'"/>

    <xsl:output indent="yes"/>

    <xsl:function name="mf:match" as="xs:string">
        <xsl:param name="input" as="xs:string"/>
        <xsl:param name="values" as="xs:string*"/>
        <xsl:sequence
            select="if ($values[matches($input, concat('^', .))])
                    then $values[matches($input, concat('^', .))]
                    else $input"/>
    </xsl:function>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="results">
        <xsl:copy>
            <xsl:for-each-group select="pageFunctionResult" group-by="mf:match(name, $values)">
                <xsl:choose>
                    <xsl:when test="name ne current-grouping-key()">
                            <xsl:copy>
                                <name>
                                    <xsl:value-of select="current-grouping-key()"/>
                                </name>
                                <variantname>
                                    <xsl:value-of select="name"/>
                                </variantname>
                                <xsl:copy-of select="id, quantity"/>
                                <xsl:apply-templates select="current-group() except ."/>
                            </xsl:copy>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:copy-of select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="pageFunctionResult">
        <variant id="{position()}">
            <xsl:apply-templates/>
        </variant>
    </xsl:template>

</xsl:transform>

Online at http://xsltransform.net/6r5Gh3R/1.

Upvotes: 1

Related Questions