使用按属性值分组转换具有某些属性的元素

Transform elements with some properties using group by attribute value

我有以下改造需求XML

<XML>
   <Obj1 attr1="value1" attr2="value2" attr="10"/>
   <Test1 tatt1="tvalue1" tatt2="tvalue2" attr="10"/>
   <Obj1 attr1="value11" attr2="value21" attr="101"/>
   <Test1 tatt1="tvalue11" tatt2="tvalue21" attr="101"/>
   <Obj1 attr1="value12" attr2="value22" attr="102"/>
   <Test1 tatt1="tvalue12" tatt2="tvalue22" attr="102"/>
</XML>

我想变身XML喜欢

<XML>
   <Obj1 attr1="value1" attr2="value2" attr="10" tatt1="tvalue1"/>
   <Obj1 attr1="value11" attr2="value21" attr="101" tatt1="tvalue11"/>
   <Obj1 attr1="value12" attr2="value22" attr="102" tatt1="tvalue12"/>
</XML>

我是通过正常的模式匹配并在所有其他元素中找到匹配的属性值来实现的。我怀疑性能。所以想检查是否可以使用 group-by 属性名称并将所有这些元素的属性合并为一个来完成。

我想将具有 attr= 的所有匹配元素的内容(Obj1 的所有属性和匹配元素的选定属性)合并到转换后的 XML。

试试这个 XSLT-1.0 样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
    <xsl:output method="xml" indent="yes"/>
    <xsl:key name="tests" match="Test1" use="@attr" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()"> <!-- Identity template: copies all nodes to the output - unless a more specific template matches -->
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Obj1">      <!-- Modifies all 'Obj1'  elements -->
        <xsl:copy>
          <xsl:copy-of select="@*|key('tests',@attr)/@tatt1" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Test1" />   <!-- Removes all 'Test1' elements from the output -->

</xsl:stylesheet>

输出应该符合要求。并且使用 xsl:key 将提高性能。

A​​FAICT,你可以这么简单:

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="/XML">
    <xsl:copy>
        <xsl:for-each select="Obj1">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="following-sibling::Test1[1]/@tatt1"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

如果你想通过匹配 attr 属性的值而不是位置来做到这一点,那么它会变成:

<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:key name="test" match="Test1" use="@attr"/>

<xsl:template match="/XML">
    <xsl:copy>
        <xsl:for-each select="Obj1">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="key('test', @attr)/@tatt1"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>