XSLT - 根据另一个属性的值创建编号属性

时间:2016-05-12 18:34:21

标签: xslt

来自以下列表的文件:

<list>
    <city ref="Paris">Paris</city>
    <city ref="Rome">Rome</city>
    <city ref="NYC">New York</city>
    <city ref="Lisboa">Lisboa</city>
    <city ref="Lisboa">Lisbon</city>
    <city ref="Lisboa">Lisbonne</city>
    <city ref="NYC">The Big Apple</city>
</list>

我想获取此列表的副本,其中添加了一个从@ref属性派生的数字属性(理想情况下按字母顺序排列),输出如下:

<list>
    <city ref="Paris" id="3">Paris</city>
    <city ref="Rome" id="4">Rome</city>
    <city ref="NYC" id="2">New York</city>
    <city ref="Lisboa" id="1">Lisboa</city>
    <city ref="Lisboa" id="1">Lisbon</city>
    <city ref="Lisboa" id="1">Lisbonne</city>
    <city ref="NYC" id="2">The Big Apple</city>
</list>

我想有一种方法可以使用<xsl:key>对我的@ref属性的排序列表进行编号,但是不够流畅到达那里。

非常感谢提前。

1 个答案:

答案 0 :(得分:1)

使用XSLT 3.0(由Saxon 9.7支持),它就像

一样简单
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:variable name="cities" select="sort(distinct-values(/list/city/@ref))"/>

    <xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="city/@ref">
        <xsl:copy/>
        <xsl:attribute name="id" select="index-of($cities, .)"/>
    </xsl:template>

</xsl:stylesheet>

使用XSLT 2.0,我们可以使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:variable name="cities" as="xs:string*">
        <xsl:perform-sort select="distinct-values(/list/city/@ref)">
            <xsl:sort select="."/>
        </xsl:perform-sort>
    </xsl:variable>

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

    <xsl:template match="city/@ref">
        <xsl:copy/>
        <xsl:attribute name="id" select="index-of($cities, .)"/>
    </xsl:template>

</xsl:stylesheet>

最后使用XSLT 1.0将上述“翻译”成

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    exclude-result-prefixes="exsl"
    version="1.0">

    <xsl:key name="city" match="city" use="@ref"/>

    <xsl:variable name="cities-rtf">
        <xsl:for-each select="/list/city[generate-id() = generate-id(key('city', @ref)[1])]">
            <xsl:sort select="@ref"/>
            <city id="{position()}" ref="{@ref}"/>
        </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="cities" select="exsl:node-set($cities-rtf)/city"/>

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

    <xsl:template match="city/@ref">
        <xsl:copy/>
        <xsl:attribute name="id">
            <xsl:value-of select="$cities[@ref = current()]/@id"/>
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>