将多个xml元素值连接到单个元素属性中

时间:2017-07-20 15:28:04

标签: xml xslt

我是XSLT的新手,我试图通过将以下元素值连接到属性来将输入xml转换为另一个。有没有办法用XSLT做到这一点?

输入xml:

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

结果xml:

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

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:2)

使用XSLT 2.0或3.0,您可以使用

<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>

答案 1 :(得分:2)

这里有其他一些方法......

<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>

<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>

答案 2 :(得分:1)

以下是XSLT-1.0解决方案 param的名称取自第一个name()元素的子requestxsl:if检查它是否是最后一个元素,如果不是,它会发出分隔符(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>

答案 3 :(得分:1)

假设所有request元素具有相同的子节点,顺序相同,我将在 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>