xsl:sort:按数值排序

Jan*_*Doe 3 sorting xslt numerical

我必须按数字顺序整理代码.代码有四个字符和四个数字.

例如,

COMP2100
COMP2400
COMP3410
LAWS2202
LAWS2250
Run Code Online (Sandbox Code Playgroud)

当我这样做<xsl:sort select="code" order="ascending" /> 时显示上面的结果.

但是,我希望它是'数字顺序'

COMP2100
LAWS2202
COMP2250
COMP2400
COMP3410
Run Code Online (Sandbox Code Playgroud)

我该怎么做呢?

ABa*_*ach 6

注意:OP现在提供了示例XML.以下理论可以简单地适应这种XML.

I. XSLT 1.0(第1部分)

这是一个简单的解决方案,假设您的断言("代码有四个字符和四个数字")将始终如此:

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

  <xsl:variable name="vNums" select="'1234567890'" />

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

  <xsl:template match="/*">
    <t>
      <xsl:apply-templates>
        <xsl:sort select="substring(., 5)"
          data-type="number" />
      </xsl:apply-templates>
    </t>
  </xsl:template>
</xsl:stylesheet> 
Run Code Online (Sandbox Code Playgroud)

...应用于想象的XML文档,随机排列:

<?xml version="1.0" encoding="utf-8"?>
<t>
  <i>COMP3410</i>
  <i>LAWS2202</i>
  <i>COMP2400</i>
  <i>COMP2100</i>
  <i>LAWS2250</i>
</t>
Run Code Online (Sandbox Code Playgroud)

...产生了正确的结果:

<?xml version="1.0" encoding="utf-8"?>
<t>
  <i>COMP2100</i>
  <i>LAWS2202</i>
  <i>LAWS2250</i>
  <i>COMP2400</i>
  <i>COMP3410</i>
</t>
Run Code Online (Sandbox Code Playgroud)

说明:

  • Identity Transform-的一个(如果不是在XSLT)最根本的设计模式-将所有从源XML文档作为-是结果XML文档节点.
  • 一个模板通过<t>根据字符串中从第5位到字符串结尾的字符对所有子项进行排序来覆盖标识变换.

再次注意,这个解决方案假设你的原始断言 - "代码有四个字符和四个数字" - 是(并且永远都是)真的.


II.XSLT 1.0(第2部分)

(可能)更安全的解决方案是假设<i>节点内的各个位置可能存在许多非数字字符.在这种情况下,这个XSLT:

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

  <xsl:variable name="vNums" select="'1234567890'" />

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

  <xsl:template match="/*">
    <t>
      <xsl:apply-templates>
        <xsl:sort select="translate(., translate(., $vNums, ''), '')"
          data-type="number" />
      </xsl:apply-templates>
    </t>
  </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

...提供相同的结果:

<?xml version="1.0" encoding="utf-8"?>
<t>
  <i>COMP2100</i>
  <i>LAWS2202</i>
  <i>LAWS2250</i>
  <i>COMP2400</i>
  <i>COMP3410</i>
</t>
Run Code Online (Sandbox Code Playgroud)

说明:

  • Identity Transform再次使用.
  • 在这种情况下,附加模板使用所谓的Double Translate Method(首先由Michael Kay提出并由Dimitre Novatchev首先向我显示)<i>在排序之前从每个元素的值中删除所有非数字字符.

III.XSLT 2.0解决方案

这是一个可能的XSLT 2.0解决方案非常类似于XSLT 1.0解决方案的第2部分; 它只是用XPath 2.0处理正则表达式的能力取代了Double Translate方法:

<xsl:sort select="replace(., '[^\d]', '')" data-type="number" />
Run Code Online (Sandbox Code Playgroud)

请注意,您无需在XPath 2.0中使用正则表达式; Double Translate方法与XPath 1.0一样有效.replace()然而,该方法最有可能更有效.