Буквенно-цифровая сортировка по смешанному строковому значению - PullRequest
1 голос
/ 02 октября 2010

Данный фрагмент XML-кода:

<forms>
<FORM lob="BO" form_name="AI OM 10"/>
<FORM lob="BO" form_name="CL BP 03 01"/>
<FORM lob="BO" form_name="AI OM 107"/>
<FORM lob="BO" form_name="CL BP 00 02"/>
<FORM lob="BO" form_name="123 DDE"/>
<FORM lob="BO" form_name="CL BP 00 02"/>
<FORM lob="BO" form_name="AI OM 98"/>
</forms>

Мне нужно отсортировать узлы FORM по алфавиту form_name, чтобы все формы, содержащие «AI OM» в имени form_name, были сгруппированы вместе, а затем внутри них они в числовом порядке по целым числам (то же самое для других форм).

Form_name может быть открыт сезон, так как буквы и цифры могут быть в любом порядке:

XX ## ##
XX XX ##
XX XX ###
XX XX ## ##
XX ###
XX XXXX
'## XXX
XXX ###

То, что я думаю, должно произойти, это то, что строка должна быть разделена между буквенным и числовым. Я думаю, что числовая часть может быть отсортирована с удалением любых пробелов.

Я в недоумении относительно того, как разбить строку, а затем охватить все комбинации сортировки / группировки, учитывая, что в отношении формата 'form_name' не существует правил.

Мы используем XSLT 2.0. Спасибо.

Ответы [ 3 ]

3 голосов
/ 02 октября 2010

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vDigits" select="'0123456789 '"/>
 <xsl:variable name="vAlpha" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ '"/>

 <xsl:template match="/*">
  <forms>
   <xsl:for-each select="FORM">
    <xsl:sort select="translate(@form_name,$vDigits,'')"/>
    <xsl:sort select="translate(@form_name,$vAlpha,'')"
        data-type="number"/>
    <xsl:copy-of select="."/>
   </xsl:for-each>
  </forms>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному XML-документу :

<forms>
    <FORM lob="BO" form_name="AI OM 10"/>
    <FORM lob="BO" form_name="CL BP 03 01"/>
    <FORM lob="BO" form_name="AI OM 107"/>
    <FORM lob="BO" form_name="CL BP 00 02"/>
    <FORM lob="BO" form_name="123 DDE"/>
    <FORM lob="BO" form_name="CL BP 00 02"/>
    <FORM lob="BO" form_name="AI OM 98"/>
</forms>

производит иск, правильный результат :

<forms>
    <FORM lob="BO" form_name="AI OM 10"/>
    <FORM lob="BO" form_name="AI OM 98"/>
    <FORM lob="BO" form_name="AI OM 107"/>
    <FORM lob="BO" form_name="CL BP 00 02"/>
    <FORM lob="BO" form_name="CL BP 00 02"/>
    <FORM lob="BO" form_name="CL BP 03 01"/>
    <FORM lob="BO" form_name="123 DDE"/>
</forms>

Обратите внимание :

  1. Две <xsl:sort> инструкции реализуют двухфазную сортировку

  2. Функция XPath translate() используется для создания либо ключа сортировки только по алфавиту, либо ключа сортировки только по цифрам.

0 голосов
/ 04 мая 2014

Следует отметить, что отмеченный ответ работает не во всех случаях.

Ввод:

<forms>
  <FORM lob="BO" form_name="AA 11 AB"/>
  <FORM lob="BO" form_name="AA AZ 01"/>
</forms>

Ожидаемый вывод:

<forms>
  <FORM lob="BO" form_name="AA AZ 01"/>
  <FORM lob="BO" form_name="AA 11 AB"/>
</forms>

Фактический вывод:

<forms>
  <FORM lob="BO" form_name="AA 11 AB"/>
  <FORM lob="BO" form_name="AA AZ 01"/>
</forms>

Если после чисел разрешены буквы, вы не можете удалить их в первом ключе сортировки.

0 голосов
/ 02 октября 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="forms">
        <xsl:apply-templates>
            <xsl:sort select="normalize-space(
                                translate(@form_name,
                                          '0123456789',
                                          ''))"/>
            <xsl:sort select="substring-before(
                                concat(
                                  normalize-space(
                                    translate(@form_name,
                                              translate(@form_name,
                                                        '0123456789 ',
                                                        ''),
                                              '')),
                                  ' '),' ')" data-type="number"/>
            <xsl:sort select="substring-after(
                                normalize-space(
                                  translate(@form_name,
                                            translate(@form_name,
                                                      '0123456789 ',
                                                      ''),
                                            '')),
                                  ' ')" data-type="number"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

Выход:

<FORM lob="BO" form_name="AI OM 10"></FORM>
<FORM lob="BO" form_name="AI OM 98"></FORM>
<FORM lob="BO" form_name="AI OM 107"></FORM>
<FORM lob="BO" form_name="CL BP 00 02"></FORM>
<FORM lob="BO" form_name="CL BP 00 02"></FORM>
<FORM lob="BO" form_name="CL BP 03 01"></FORM>
<FORM lob="BO" form_name="123 DDE"></FORM>

Решение XSLT 2.0: эта таблица стилей

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="forms">
        <xsl:apply-templates>
            <xsl:sort select="string-join(tokenize(@form_name,' ')
                                            [not(. castable as xs:integer)],
                                          ' ')"/>
            <xsl:sort select="xs:integer(tokenize(@form_name,' ')
                                            [. castable as xs:integer][1])"/>
            <xsl:sort select="xs:integer(tokenize(@form_name,' ')
                                            [. castable as xs:integer][2])"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>
...