1

I have the following XML:

<root>
    <attributes>
        <attribute_value>ID1</attribute_value>
        <attribute_name>id</attribute_name>
    </attributes>
    <attributes>
        <attribute_value>ID2</attribute_value>
        <attribute_name>id</attribute_name>
    </attributes>
    <attributes>
        <attribute_value>some-link</attribute_value>
        <attribute_name>link</attribute_name>
    </attributes>
</root>

I want to iterate over the file and concatenate all the "attribute_value" values based on the "attribute_name" value using XSLT (1.0 or 2.0). So in this case the output would be:

<root>
    <element name="id" value="ID1"/>
    <element name="ids" value="ID1,ID2"/>
    <element name="link" value="some-link"/>
</root>

The "id" element should contain the first value encountered and the "ids" element would contain the concatenated value. How can this be achieved? I have a working XSLT where I use the tag and iterate over all the attributes, but not able to get around this problem.

The following is my current XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" version="1.0" indent="yes"/>
        <xsl:template match="root">
            <root>
                <xsl:for-each select="attributes">  
                    <xsl:variable name="attribute_name" select="attribute_name"/>
                    <xsl:variable name="attribute_value" select="attribute_value"/>
                    <xsl:if test="$attribute_name = 'link'">
                        <element name="link">
                            <xsl:attribute name="value"><xsl:value-of select="$attribute_value" /></xsl:attribute>
                        </element>
                    </xsl:if>
                </xsl:for-each>
            </root>
        </xsl:template>
    </xsl:stylesheet>
4
  • Can you show the XSLT you currently have? Thank you! Commented Sep 10, 2015 at 12:40
  • There are only two distinct attribute_name values in your input; why do you have three element nodes in the output? Commented Sep 10, 2015 at 12:42
  • @TimC: Added the XSLT. Commented Sep 10, 2015 at 13:00
  • @michael.hor257k: As explained, I need two elements, "id" for first id encountered and "ids" which will contain concatenated values. Commented Sep 10, 2015 at 13:00

1 Answer 1

2

As you are using XSLT 2.0, you can use xsl:for-each-group here

<xsl:for-each-group select="attributes" group-by="attribute_name">  

Then to output the first element, you can do this:

 <element name="{attribute_name}" value="{attribute_value}" />

(Note the use of attribute value templates to simplify creating the attributes)

Then if there are more than one element in the group, you could create the concatenated version like so:

<element name="{@attribute_name}s" value="{string-join(current-group()/attribute_value, ',')}" />

Try this XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" indent="yes"/>
    <xsl:template match="root">
        <root>
            <xsl:for-each-group select="attributes" group-by="attribute_name">  
                <element name="{attribute_name}" value="{attribute_value}" />
                <xsl:if test="current-group()[2]">
                    <element name="{@attribute_name}s" value="{string-join(current-group()/attribute_value, ',')}" />
                </xsl:if>
            </xsl:for-each-group>
        </root>
    </xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! This works great! Your answer is short and simple. Just a note, I used "{attribute_name}s" instead of "{@attribute_name}s" inside the test condition to pluralise the attribute name.
Yes, attribute_name is correct. The use of @ was a typo in my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.