代码之家  ›  专栏  ›  技术社区  ›  scunliffe

如何在XSLT中应用字母数字排序

  •  2
  • scunliffe  · 技术社区  · 15 年前

    基于以下XML,在XSL中实现字母数字排序的最佳方法是什么?

    编辑 :为了澄清,下面的XML只是一个简单的示例,实际的XML将包含更多的变量值。

    <colors>
      <item>
        <label>Yellow 100</label>
      </item>
      <item>
        <label>Blue 12</label>
      </item>
      <item>
        <label>Orange 3</label>
      </item>
      <item>
        <label>Yellow 10</label>
      </item>
      <item>
        <label>Orange 26</label>
      </item>
      <item>
        <label>Blue 117</label>
      </item>
    </colors>
    

    例如,我希望按以下顺序得出最终结果:

    Blue 12, Blue 117, Orange 3, Orange 26, Yellow 10, Yellow 100
    

    这是“ 有效地 “我想要什么。

    <xsl:apply-templates select="colors/item">
      <xsl:sort select="label" data-type="text" order="ascending"/><!--1st sort-->
      <xsl:sort select="label" data-type="number" order="ascending"/><!--2nd sort-->
    </xsl:apply-templates>   
    
    <xsl:template match="item">
      <xsl:value-of select="label"/>
      <xsl:if test="position() != last()">,</xsl:if>
    </xsl:template>
    
    1 回复  |  直到 15 年前
        1
  •  6
  •   Dirk Vollmar    15 年前

    使用将标签文本拆分为文本并对零件编号 substring-before substring-after 在您的示例中可以这样做(但是,这不是一般方法,但您已经了解了这个想法):

    <xsl:template match="/">
        <xsl:apply-templates select="colors/item">
          <xsl:sort select="substring-before(label, ' ')" data-type="text" order="ascending"/>
          <!--1st sort-->
          <xsl:sort select="substring-after(label, ' ')" data-type="number" order="ascending"/>
          <!--2nd sort-->
        </xsl:apply-templates>
      </xsl:template>
    
      <xsl:template match="item">
        <xsl:value-of select="label"/>
        <xsl:if test="position() != last()">, </xsl:if>
      </xsl:template>
    

    这将提供以下输出:

    Blue 12, Blue 117, Orange 3, Orange 26, Yellow 10, Yellow 100
    

    更新

    解决排序问题的一个更通用的方法是 select 的属性 xls:sort 元素包含一个字符串,该字符串可以根据预期的排序规则进行排序。例如,在这个字符串中,所有数字都可以用前导0填充,以便在词汇上将它们排序为 data-type="text" 将导致正确的字母数字顺序。

    如果您使用的是.NET的XSLT引擎,则可以使用C中的简单扩展函数来填充前导为0的数字:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:myExt="urn:myExtension"
                    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                    exclude-result-prefixes="msxsl myExt">
      <xsl:output method="xml" indent="yes" />
    
      <msxsl:script language="C#" implements-prefix="myExt">
    
        <![CDATA[
            private static string PadMatch(Match match)
            {
                // pad numbers with zeros to a maximum length of the largest int value 
                int maxLength = int.MaxValue.ToString().Length;
                return match.Value.PadLeft(maxLength, '0');
            }
    
            public string padNumbers(string text)
            {
                return System.Text.RegularExpressions.Regex.Replace(text, "[0-9]+", new System.Text.RegularExpressions.MatchEvaluator(PadMatch));
            }
        ]]>
    
      </msxsl:script>
      <xsl:template match="/">
        <sorted>
          <xsl:apply-templates select="colors/item">
            <xsl:sort select="myExt:padNumbers(label)" data-type="text" order="ascending"/>
          </xsl:apply-templates>
        </sorted>
      </xsl:template>
    
      <xsl:template match="item">
        <xsl:value-of select="label"/>
        <xsl:if test="position() != last()">, </xsl:if>
      </xsl:template>
    
    </xsl:stylesheet>