生成按字母顺序排序的序列

时间:2020-12-21 17:59:45

标签: xslt-2.0 xpath-2.0

是否有内置或简单的方法来生成按字母顺序排序的值序列?

例如,以下 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>

2 个答案:

答案 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"/>