xml复杂节点通过xslt合并

问题描述 投票:0回答:1

我需要根据属性值通过xslt合并两个复杂元素节点,即例如当id = 1时,需要合并其各自的名称值元素。所以对于id = 2,3 ..等等

<?xml version="1.0" encoding="UTF-8"?>
<xrefStore>
<xrefData>
    <entityData>
        <entry id="1">
            <keyValue name="A" value=" "/>
            <keyValue name="B" value=" "/>
            <keyValue name="C" value=" "/>
        </entry>
        <entry id="2">
            <keyValue name="A" value=" "/>
            <keyValue name="B" value=" "/>
            <keyValue name="c" value=" "/>
            <keyValue name="D" value=" "/>
            <keyValue name="E" value=" "/>
        </entry>
        <entry id="1">
            <keyValue name="D" value=" "/>
            <keyValue name="E" value=" "/>
        </entry>
    </xrefStore>
</xrefData>

最终输出应如下,

<?xml version="1.0"?>
<root>
<set id="1">
    <nameValuePair>
        <name>A</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>B</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>C</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>D</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>E</name>
        <value> </value>
    </nameValuePair>
</set>
<set id="2">
    <nameValuePair>
        <name>A</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>B</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>C</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>D</name>
        <value> </value>
    </nameValuePair>
    <nameValuePair>
        <name>E</name>
        <value> </value>
    </nameValuePair>
</set>
</root>

我已经尝试了下面的代码,但它没有基于id合并。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <root>
        <xsl:for-each select="xrefStore/xrefData/entityData/entity/entry">
            <set >
                <xsl:attribute name="id">
                    <xsl:value-of select="current()/@id" />
                </xsl:attribute>
                <xsl:for-each select="current()/keyValue">
                    <nameValuePair>
                        <name>
                            <xsl:value-of select="current()/@name" />
                        </name>
                        <value>
                            <xsl:value-of select="current()/@value" />
                        </value>
                    </nameValuePair>
                </xsl:for-each>
            </set>
        </xsl:for-each>
    </root>
    </xsl:template>
</xsl:stylesheet>

任何形式的帮助表示赞赏。

我在这里找到了类似的答案,Merge XML nodes using XSLT

但我不明白他们实施的概念。

xml xslt merge
1个回答
1
投票

虽然这个问题已经有几个月的历史了,但是考虑发布一个答案,以便它可能对其他可能碰巧遇到这个问题的人有用。

XSLT 1.0解决方案

需要声明一个密钥,该密钥将用于对相同节点进行分组。在示例中,需要在id元素的<entry>属性上进行分组。

<xsl:key name="kId" match="entry" use="@id" />

需要对所有<entry>节点进行循环,其唯一标识符(由generate-id()函数返回)与密钥的唯一标识符匹配。

<xsl:for-each select="entry[generate-id() = generate-id(key('kId', @id)[1])]">

最后循环遍历分组键中的所有<keyValue>节点以获得所需结果。

<xsl:for-each select="key('kId',@id)/keyValue">

使用版本1.0的完整XSL如下所示。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*"/>

    <!-- declare key to group nodes -->
    <xsl:key name="kId" match="entry" use="@id" />

    <xsl:template match="entityData">
        <root>
            <!-- loop through the grouped keys -->
            <xsl:for-each select="entry[generate-id() = generate-id(key('kId', @id)[1])]">
                <set>
                    <xsl:attribute name="id">
                        <xsl:value-of select="@id" />
                    </xsl:attribute>
                    <!-- loop through the elements of the key -->
                    <xsl:for-each select="key('kId',@id)/keyValue">
                        <nameValuePair>
                            <name>
                                <xsl:value-of select="@name" />
                            </name>
                            <value>
                                <xsl:value-of select="@value" />
                            </value>
                        </nameValuePair>
                    </xsl:for-each>
                </set>
            </xsl:for-each>
        </root>     
    </xsl:template>
</xsl:stylesheet>

XSLT 2.0解决方案

2.0版使用grouping功能为<xsl:for-each-group>提供了一种更简单的方法。下面是XSL。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="entityData">
        <root>
            <!-- loop through 'entry' groups grouped by 'id' attribute -->
            <xsl:for-each-group select="entry" group-by="@id">
                <set>
                    <xsl:attribute name="id">
                        <xsl:value-of select="current-grouping-key()" />
                    </xsl:attribute>
                    <!-- loop through current group for all 'keyValue' elements -->
                    <xsl:for-each select="current-group()/keyValue">
                        <nameValuePair>
                            <name>
                                <xsl:value-of select="@name" />
                            </name>
                            <value>
                                <xsl:value-of select="@value" />
                            </value>
                        </nameValuePair>
                    </xsl:for-each>
                </set>
            </xsl:for-each-group>
        </root> 
    </xsl:template>
</xsl:stylesheet>

两种解决方案都将输入XML转换为所需的输出

<root>
   <set id="1">
      <nameValuePair>
         <name>A</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>B</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>C</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>D</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>E</name>
         <value> </value>
      </nameValuePair>
   </set>
   <set id="2">
      <nameValuePair>
         <name>A</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>B</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>c</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>D</name>
         <value> </value>
      </nameValuePair>
      <nameValuePair>
         <name>E</name>
         <value> </value>
      </nameValuePair>
   </set>
</root>
© www.soinside.com 2019 - 2024. All rights reserved.