是否有内置或简单的方法来生成按字母顺序排序的值序列?
例如,以下 item 元素具有用于排序的子序列元素。正在为需要此信息的另一个系统生成数据,因为它不适用于文档排序。
<list>
<item>
<sequence>1</sequence>
</item>
<item>
<sequence>2</sequence>
</item>
<item>
<sequence>3</sequence>
</item>
<item>
<sequence>4</sequence>
</item>
...
<item>
<sequence>14</sequence>
</item>
<item>
<sequence>15</sequence>
</item>
系统不是按数字排序,而是按字母顺序排序,并且无法更改此行为。结果项目被排序为 1,10,11,12,13,14,15,2,3,4,5,6,7,8,9
此外,项目的实际数量是无限的,因此需要有一种通用的方法来生成一个按正确顺序排序的字母序列。也就是说,项目的数量应该相对较少,在 1000 以下。
这是我目前所拥有的:
<xsl:variable name="idchars" as="xs:string *"
select="
('0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z')
"
/>
<xsl:variable name="idlen" as="xs:integer" select="count($idchars)" />
<xsl:function name="f:genId" as="xs:string">
<xsl:param name="pSeq" as="xs:integer" />
<xsl:variable name="vLen" as="xs:integer" select="$pSeq idiv $idlen" />
<xsl:value-of>
<xsl:for-each select="1 to $vLen">
<xsl:sequence select="$idchars[$idlen]" />
</xsl:for-each>
<xsl:sequence select="$idchars[$pSeq mod $idlen]" />
</xsl:value-of>
</xsl:function>
答案 0 :(得分:0)
您可以使用 format-number()
来生成具有可变长度的前导零的左填充数字序列,然后使用 codepoints-to-string()
将这些数字中的每一个转换为一个字母,然后将它们连接起来连同string-join()
:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="local">
<xsl:output indent="yes"/>
<xsl:function name="f:genId" as="xs:string">
<xsl:param name="pSeq" as="xs:integer" />
<xsl:param name="digits" as="xs:integer"/>
<xsl:variable name="picture" select="string-join( ((1 to $digits) ! '0'), '')" />
<xsl:variable name="padded-string" select="format-number($pSeq, $picture)" as="xs:string"/>
<xsl:variable name="padded-letter-seq" select="(1 to string-length($picture)) ! substring($padded-string, ., 1) ! codepoints-to-string(xs:integer(.) + 65)" as="xs:string*"/>
<xsl:sequence select="string-join($padded-letter-seq, '')"/>
</xsl:function>
<xsl:function name="f:genId" as="xs:string">
<xsl:param name="pSeq" as="xs:integer"/>
<xsl:sequence select="f:genId($pSeq, 4)"/>
</xsl:function>
<xsl:template match="/">
<xsl:sequence select="f:genId(3)"/>
<xsl:sequence select="f:genId(3,5)"/>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
只需使用 <xsl:sort>
xslt 元素,就像这样:
<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:template match="/*">
<xsl:copy>
<xsl:apply-templates select="*">
<xsl:sort select="sequence"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<list>
<item>
<sequence>1</sequence>
</item>
<item>
<sequence>2</sequence>
</item>
<item>
<sequence>3</sequence>
</item>
<item>
<sequence>4</sequence>
</item>
...
<item>
<sequence>14</sequence>
</item>
<item>
<sequence>15</sequence>
</item>
</list>
产生想要的、正确的结果:
<list>
<item>
<sequence>1</sequence>
</item>
<item>
<sequence>14</sequence>
</item>
<item>
<sequence>15</sequence>
</item>
<item>
<sequence>2</sequence>
</item>
<item>
<sequence>3</sequence>
</item>
<item>
<sequence>4</sequence>
</item>
</list>
请注意:
这个:
<xsl:sort select="sequence"/>
相当于:
<xsl:sort select="sequence" data-type="text"/>
因为“文本”是 data-type
属性的默认值。
如果需要对数字进行排序,应明确使用:
<xsl:sort select="sequence" data-type="number"/>