0

I'm new to XSLT and I'm trying to transform an input xml into an other by concatenating the following element values into attributes. Is there a way I can do this with XSLT?

Input xml:

<requests>
  <request>
    <name>BLA1</name>
    <age>42</age>
  </request>
  <request>
    <name>BLA2</name>
    <age>24</age>
  </request>
</requests>

Result xml:

<bodyParams>
    <param name='name' value='BLA1,BLA2' />
    <param name='age' value='42,24' />
</bodyParams>

Thank you for the help in advance!

1
  • Do you use XSLT 1.0 or 2.0? Commented Jul 20, 2017 at 15:39

4 Answers 4

2

Using XSLT 2.0 or 3.0 you could use

<xsl:template match="requests">
    <bodyParams>
        <xsl:for-each-group select="request/*" group-by="node-name(.)">
            <param name="{current-grouping-key()}" value="{string-join(current-group(), ',')}"/>
        </xsl:for-each-group>
    </bodyParams>
</xsl:template>
Sign up to request clarification or add additional context in comments.

Comments

2

Here some other method...

<xsl:template match="requests">
       <xsl:variable name="name">
            <xsl:value-of select="for $x in . return if ($x//name) then $x//name else ''" separator=","/>
        </xsl:variable>
        <xsl:variable name="age">
            <xsl:value-of select="for $x in . return if ($x//age) then $x//age else ''" separator=","/>
        </xsl:variable>
        <bodyparams>
            <param name="name" value="{$name}"/>
            <param name="age" value="{$age}"/>
        </bodyparams>
    </xsl:template>

or

<xsl:template match="requests">
        <xsl:variable name="name">
            <xsl:value-of select="for $x in . return if ($x/request/*[1]) then $x/request/*[1] else ''" separator=","/>
        </xsl:variable>
        <xsl:variable name="age">
            <xsl:value-of select="for $x in . return if ($x/request/*[2]) then $x/request/*[2] else ''" separator=","/>
        </xsl:variable>
        <bodyparams>
            <param name="name" value="{$name}"/>
            <param name="age" value="{$age}"/>
        </bodyparams>
    </xsl:template>

1 Comment

IMHO, name and age are just an example and not meant to be hard-coded.
1

The following is an XSLT-1.0 solution.
The param's names are taken from the children's name() of the first request element. The xsl:if checks if it's the last element, if not, it emits the delimiter (delimiter in XSLT-1.0).

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  

<xsl:template match="/requests">
    <bodyParams>
      <xsl:for-each select="request[1]/*">              <!-- iterate over children's names of the first request element -->
        <xsl:variable name="curPos" select="name()" />  <!-- remember its name -->
        <xsl:element name="param">                      <!-- construct <param name="..." value="..." /> element -->
            <xsl:attribute name="name"><xsl:value-of select="name()" /></xsl:attribute>
            <xsl:attribute name="value"><xsl:for-each select="//request/*[name()=$curPos]">
              <xsl:value-of select="normalize-space(.)" /><xsl:if test="position() != last()"><xsl:text>,</xsl:text></xsl:if>
            </xsl:for-each></xsl:attribute>
        </xsl:element>
      </xsl:for-each>
      <xsl:apply-templates select="@*|node()" />
    </bodyParams>
</xsl:template>

<xsl:template match="text()" />
</xsl:stylesheet>

1 Comment

Sorry I forgot to mention I needed the 1.0 solution. Thank you for your answer this solved my problem.
1

Assuming all request elements have the same child nodes, in the same order, this is how I would solve this in XSLT 1.0:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/requests">
    <bodyParams>
        <xsl:for-each select="request[1]/*">
            <xsl:variable name="i" select="position()" />
            <param name="{name()}">
                <xsl:attribute name="value">
                    <xsl:for-each select="../../request/*[$i]">
                        <xsl:value-of select="." />
                        <xsl:if test="position()!=last()">
                            <xsl:text>,</xsl:text>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:attribute>
            </param>
        </xsl:for-each>
    </bodyParams>
</xsl:template>

</xsl:stylesheet>

Comments

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.