【问题标题】:Concatenate multiple xml element values into a single element attribute将多个 xml 元素值连接到单个元素属性中
【发布时间】:2017-07-21 19:47:59
【问题描述】:

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

提前感谢您的帮助!

【问题讨论】:

  • 您使用 XSLT 1.0 还是 2.0?

标签: xml xslt


【解决方案1】:

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

【讨论】:

    【解决方案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>
    

    【讨论】:

    • 恕我直言,nameage 只是一个示例,并不意味着硬编码。
    【解决方案3】:

    以下是 XSLT-1.0 解决方案。
    param 的名称取自第一个 request 元素的子 name()xsl: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>
    

    【讨论】:

    • 对不起,我忘了说我需要 1.0 解决方案。感谢您的回答,这解决了我的问题。
    【解决方案4】:

    假设所有 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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多