двойная сортировка в xslt по двум разным полям

#xml #xslt

#xml #xslt

Вопрос:

Я хотел бы отсортировать свой XML-файл по двум признакам: идентификатору и влиянию. Я хотел бы упорядочить элементы по идентификатору, ЗА исключением элементов, у которых есть XX product, который должен появиться последним.

Мой XML-файл

 <evolutionlist>
<date>
    <object>
        <identifier>id5</identifier>
        <impact>
            <product>AA</produit>
        </impact>
    </objet>
    <object>
        <identifier>id2</identifier>
        <impact>
            <product>XX</produit>
        </impact>
    </objet>
    <object>
        <identifier>id4</identifier>
        <impact>
            <product>BB</produit>
        </impact>
    </objet>
   <object>
        <identifier>id3</identifier>
        <impact>
            <product>XX</produit>
        </impact>
    </objet>
    <object>
        <identifier>id1</identifier>
        <impact>
            <product>CC</produit>
        </impact>
    </objet>
 </date>
 </evolutionlist>
 

Ожидаемый результат будет:

 <evolutionlist>
<date>
    <object>
        <identifier>id1</identifier>
        <impact>
            <product>CC</produit>
        </impact>
    </objet>
    <object>
        <identifier>id4</identifier>
        <impact>
            <product>BB</produit>
        </impact>
    </objet>
    <object>
        <identifier>id5</identifier>
        <impact>
            <product>AA</produit>
        </impact>
    </objet>
   <object>
        <identifier>id2</identifier>
        <impact>
            <product>XX</produit>
        </impact>
    </objet>
    <object>
        <identifier>id3</identifier>
        <impact>
            <product>XX</produit>
        </impact>
    </objet>
 </date>
 </evolutionlist>
 

мой код xslt (хотя и не работает)

 <xsl:for-each  select="//date">
   <tr>
  <td>
     <xsl:value-of select="./@id"/>
  </td>
   </tr>
   <xsl:for-each select="./object">
   <xsl:choose>
    <xsl:when test="impact/produit = 'XX'">
            <xsl:sort select="impact/produit" order="descending"/>
    </xsl:when>
    <xsl:otherwise>
        <xsl:sort select="identifiant"/>
    </xsl:otherwise>
   </xsl:choose>

        ...
 </xsl:for-each>
 

Ответ №1:

Вы можете поместить a <xsl:sort> в начало <xsl:for-each> или <xsl:apply-templates/> , а не в <choose> блок.

Вы используете сортировку для упорядочивания XX , поэтому я предполагаю, что в вашем сценарии это нормально (например: у вас нет имени продукта ZZ , которое было бы помещено после XX ). Если это не так, вам следует использовать не sort для этого правила, а шаблон, который соответствует XX содержимому и помещает его в конец.

Эта таблица стилей выдает ожидаемые результаты, используя sort правила, которые у вас есть в исходной таблице стилей (упорядочение по идентификаторам и строкам продуктов). Я переместил правила выбора в предикат XPath и использовал шаблоны вместо вложенных for-each узлов.

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="date">
            <xsl:apply-templates select="object">
                <xsl:sort select="impact/product[. = 'XX']" order="ascending"/>
                <xsl:sort select="identifier"/>
            </xsl:apply-templates>
    </xsl:template>

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

</xsl:stylesheet>
 

Вы можете попробовать это в этой скрипке XSLT

ОБНОВЛЕНИЕ В случае, если вы на самом деле не хотите заказывать XX продукты, но всегда размещаете их в конце, вы можете отфильтровать эти элементы и применить их шаблоны после обработки других элементов. Это делает другая таблица стилей:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="date">
        <xsl:apply-templates select="object[not(impact[product = 'XX'])]">
            <xsl:sort select="identifier"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="object[impact[product = 'XX']]"/>
    </xsl:template>

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

</xsl:stylesheet>
 

Вот еще одна скрипка XSLT с этим примером.

Комментарии:

1. спасибо за помощь, это более понятно, к сожалению, у меня могут быть продукты ZZ, которые должны быть отсортированы по их идентификатору, в конце должны отображаться только продукты XX, извините, я был недостаточно точен

2. вот почему я использовал условие «когда»

3. Вам не нужно when . Вы можете выбирать с помощью шаблонов и предикатов, что также более эффективно. Я добавил решение, помещающее XX элементы в конец.

4. большое спасибо! Это именно то, что мне нужно, решение очень четкое!

5. и спасибо за подсказку по скрипке XSLT! Я этого не знал !