3

我有这个需要用 xslt 转换的输入 XML

<root>
    <node id="a">
        <section id="a_1" method="run">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_2">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_1" method="run">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
    </node>
    <node id="b">
        <section id="b_1" method="create">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
            <user id="b_1b">
                <attribute>a</attribute>
            </user>
        </section>
        <section id="b_1" method="create">
            <user id="b_1c">
                <attribute>a</attribute>
            </user>
        </section>
        <section id="b_2">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
        </section>
    </node>
</root>

预期输出:

<root>
    <node id="a">
        <section id="a_1">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_2">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
    </node>
    <node id="b">
        <section id="b_1" method="create">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
            <user id="b_1b">
                <attribute>a</attribute>
            </user>
        </section>

        <section id="b_2">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
        </section>
    </node>
</root>

淘汰哪个节点无关紧要,只要元素名称、id和方法相同,其中一个就会被淘汰。知道 xsl 是什么样子的吗?

注意:元素名称可以是任何东西,不必是,并且在整个文件中有多个元素名称;只要它具有相同的元素名称、id 和属性(例如 method=create),其中之一就会被淘汰。

非常感谢。干杯,约翰

4

2 回答 2

3

I. 这是一个简短而有效的(使用键)XSLT 1.0 转换:

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

 <xsl:key name="kElemWithAttribs" match="*[@id and @method]"
  use="concat(name(), '+', @id, '+', @method)"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "*[@id and @method
    and
     not(generate-id()
        =
         generate-id(key('kElemWithAttribs',
                         concat(name(), '+', @id, '+', @method)
                         )[1]
                    )
         )
     ]"/>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<root>
    <node id="a">
        <section id="a_1" method="run">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_2">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_1" method="run">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
    </node>
    <node id="b">
        <section id="b_1" method="create">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
            <user id="b_1b">
                <attribute>a</attribute>
            </user>
        </section>
        <section id="b_1" method="create">
            <user id="b_1c">
                <attribute>a</attribute>
            </user>
        </section>
        <section id="b_2">
            <user id="b_1a">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
        </section>
    </node>
</root>

产生了想要的正确结果:

<root>
   <node id="a">
      <section id="a_1" method="run">
         <item id="0">
            <attribute>
               <color>Red</color>
            </attribute>
         </item>
      </section>
      <section id="a_2">
         <item id="0">
            <attribute>
               <color>Red</color>
            </attribute>
         </item>
      </section>
   </node>
   <node id="b">
      <section id="b_1" method="create">
         <user id="b_1a">
            <attribute>
               <name>John</name>
            </attribute>
         </user>
         <user id="b_1b">
            <attribute>a</attribute>
         </user>
      </section>
      <section id="b_2">
         <user id="b_1a">
            <attribute>
               <name>John</name>
            </attribute>
         </user>
      </section>
   </node>
</root>

说明

使用Muenchian 方法使用复合键进行分组。在这里,我们忽略(删除)不是组中第一个的每个节点。


二、XSLT 2.0 解决方案——甚至更短且效率不低

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="node">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>

    <xsl:for-each-group select="*"
         group-by="concat(name(), '+', @id, '+', @method)">
      <xsl:apply-templates select="."/>
    </xsl:for-each-group>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

说明

正确使用xsl:for-each-groupwithgroup-by属性。

于 2012-04-22T14:32:41.090 回答
1

XSL 文件:

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

<xsl:template match="/">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="root">
    <root>
        <xsl:apply-templates/>
    </root>
</xsl:template>

<xsl:template match="node">
    <node>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </node>
</xsl:template>

<xsl:template match="section[@id = 'b_1'][1]">  
    <section>
        <xsl:copy-of select="node()|@*"/>
    </section>  
</xsl:template>

<xsl:template match="section[@id != 'b_1']">
    <section>       
        <xsl:copy-of select="node()|@*"/>
    </section>
</xsl:template>

<xsl:template match="section[@id = 'b_1'][position() &gt; 1]"/> 

</xsl:stylesheet>

转变:

<root>
        <node id="a">
            <section id="a_1">
                <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
                </item>
            </section>
            <section id="a_2">
                <item id="0">
                    <attribute>
                        <color>Red</color>
                    </attribute>
                </item>
            </section>
        </node>
        <node id="b">
            <section id="b_1" method="create">
                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>
                <user id="b_1b">
                    <attribute>a</attribute>
                </user>
            </section>
            <section id="b_2">
                <user id="b_1a">
                    <attribute>
                        <name>John</name>
                    </attribute>
                </user>
            </section>
        </node>
    </root>

希望这可以帮助。

[编辑] 在同一个输入文件上试试这个 XSL:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="*[not(@id eq preceding::*[local-name() eq local-name(.)]/@id)]">
        <xsl:element name="{name()}">
            <xsl:copy-of select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

结果:

<root>
  <node id="a">
    <section id="a_1">
      <item id="0">
        <attribute>
          <color>Red</color>
        </attribute>
      </item>
    </section>
    <section id="a_2">
      <item id="0">
        <attribute>
          <color>Red</color>
        </attribute>
      </item>
    </section>
  </node>
  <node id="b">
    <section id="b_1" method="create">
      <user id="b_1a">
        <attribute>
          <name>John</name>
        </attribute>
      </user>
      <user id="b_1b">
        <attribute>a</attribute>
      </user>
    </section>
    <section id="b_1" method="create">
      <user id="b_1c">
        <attribute>a</attribute>
      </user>
    </section>
    <section id="b_2">
      <user id="b_1a">
        <attribute>
          <name>John</name>
        </attribute>
      </user>
    </section>
  </node>
</root>

[/编辑]

于 2012-04-22T08:37:59.713 回答