使用XSLT将XML排序为集合和元素

时间:2014-08-01 19:23:17

标签: xml sorting xslt

我有一个包含集合定义和元素定义的xml文档。示例XML:

<!-- a set definition -->
<a name="SET.1" mnemonic="NAME_SET" ... />
<!-- an element definition -->
<a name="NAME_SET.1" mnemonic="Element1" .../>

我无法控制进入的xml。判断集合定义和元素定义之间区别的唯一方法是name属性的值。在集合定义中,它将以“SET”开头;在元素定义中,它将以set的助记符属性的值开始。

我想使用XSLT按集合排序文件,然后按集合中的元素排序。含义:

<!-- a set definition -->
<a name="SET.1" mnemonic="ANIMAL_SET" ... />
<!-- an element definition -->
<a name="ANIMAL_SET.1" mnemonic="Mouse" .../>
... all the elements in ANIMAL_SET

<!-- a set definition -->
<a name="SET.2" mnemonic="VEHICLE_SET" ... />
<!-- an element definition -->
<a name="VEHICLE_SET.1" mnemonic="Car" .../>
... all the elements in VEHICLE_SET

我相信要这样做,我会使用<xsl:for-each>,但我不确定如何。有什么想法吗?

编辑以更清楚地解释我的样本xml:

原始xml:

<ExternalTag attribute="00061000">
    <TagOnSameLevel attribute="foo"/>
    <a attribute="1" mnemonic="CAR_SET" name="SET.102" />
    <a attribute="3" mnemonic="Toyota" name="CAR_SET.3" />
    <a attribute="11" mnemonic="lion" name="ANIMAL_SET.12" />
    <a attribute="2" mnemonic="Chevy" name="CAR_SET.2" />
    <a attribute="2" mnemonic="ANIMAL_SET" name="SET.1034" />
    <a attribute="6" mnemonic="tiger" name="ANIMAL_SET.6" />
</ExternalTag>

xslt后的所需xml:按名称排序的SET,每组中的元素也按名称排序。

<ExternalTag attribute="00061000">
    <TagOnSameLevel attribute="foo"/>
    <a attribute="1" mnemonic="CAR_SET" name="SET.102" />
    <a attribute="2" mnemonic="Chevy" name="CAR_SET.2" />
    <a attribute="3" mnemonic="Toyota" name="CAR_SET.3" />
    <a attribute="2" mnemonic="ANIMAL_SET" name="SET.1034" />
    <a attribute="11" mnemonic="lion" name="ANIMAL_SET.12" />
    <a attribute="6" mnemonic="tiger" name="ANIMAL_SET.6" />
</ExternalTag>

1 个答案:

答案 0 :(得分:2)

这是你可以做到的一种方式:

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="/">
    <output>
        <xsl:for-each select="input/a[starts-with(@name, 'SET.')]">
            <xsl:copy-of select="."/>
            <xsl:for-each select="../a[starts-with(@name, current()/@mnemonic)]">
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

鉴于格式良好的测试输入

<input>
    <a name="SET.1" mnemonic="ANIMAL_SET"/>
    <a name="SET.2" mnemonic="VEHICLE_SET"/>
    <a name="ANIMAL_SET.1" mnemonic="Mouse" />
    <a name="VEHICLE_SET.1" mnemonic="Car"/>
    <a name="ANIMAL_SET.1" mnemonic="Cat" />
    <a name="VEHICLE_SET.1" mnemonic="Truck"/>
</input>

结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <a name="SET.1" mnemonic="ANIMAL_SET"/>
   <a name="ANIMAL_SET.1" mnemonic="Mouse"/>
   <a name="ANIMAL_SET.1" mnemonic="Cat"/>
   <a name="SET.2" mnemonic="VEHICLE_SET"/>
   <a name="VEHICLE_SET.1" mnemonic="Car"/>
   <a name="VEHICLE_SET.1" mnemonic="Truck"/>
</output>

更智能的输出形式会将每个组包装在组合元素中。


修改

鉴于您的更新输入,请尝试这种方式:

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:strip-space elements="*"/>

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

<xsl:template match="/ExternalTag">
    <xsl:copy>
        <xsl:apply-templates select="@* | *[not(self::a)] | a[starts-with(@name, 'SET.')]"/>
    </xsl:copy>
</xsl:template>   

<xsl:template match="a">
    <xsl:copy-of select="."/>
        <xsl:for-each select="../a[starts-with(@name, current()/@mnemonic)]">
            <xsl:copy-of select="."/>
        </xsl:for-each>
</xsl:template>

</xsl:stylesheet>