Как применить алфавитно-цифровую сортировку в XSLT - PullRequest
2 голосов
/ 22 апреля 2009

На основании следующего 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 Ответ

6 голосов
/ 22 апреля 2009

Разделение текста метки на текстовую и числовую части с использованием 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 содержал строку, которую можно сортировать в соответствии с ожидаемыми правилами сортировки. Например. в этой строке все числа могут быть дополнены начальными нулями, так что лексикографическая сортировка их по data-type="text" приведет к правильному алфавитно-цифровому порядку.

Если вы используете XSLT-движок .NET, вы можете использовать простую функцию расширения в 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...