XSLT xsl: проблема сортировки - PullRequest
1 голос
/ 23 апреля 2011

У меня есть XML-файл, который мне нужно отсортировать. Работал отлично, пока разработчик не потребовал, чтобы он сказал мне изменить XML на элементы, которые у меня были, с атрибутами type = label для обозначения узлов. Не отлично в XSLT. Необходимо отсортировать по узлу 'sort'.

(упрощенный) XML выглядит следующим образом:

<rss>
   <channel>
       <title>This is the title</title>
       <link>http://www.mydomain.com/</link>
       <description>The Description</description>
       <label>
           <title>Another Label</title>
           <sort>4</sort>
       </label>
       <item>
           <title>An Item</title>
           <sort>2</sort>
       </item>
       <item>
           <title>One Item</title>
           <sort>3</sort>
       </item>
       <label>
           <title>A Label</title>
           <sort>1</sort>
       </label>
   </channel>
</rss>

Старый XSL (когда я просто сортировал «элементы») выглядит примерно так:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" encoding="UTF-8" indent="yes" />
     <xsl:template match="channel">
        <rss>
           <channel>
              <xsl:copy-of select="title"/>
              <xsl:copy-of select="link"/>
              <xsl:copy-of select="description"/>
              <xsl:apply-templates select="item">
                  <xsl:sort select="sort" data-type="number"/>
              </xsl:apply-templates>
           </channel>
        </rss>
    </xsl:template>

    <xsl:template match="item">
        <xsl:copy-of select="." />
    </xsl:template> 
 </xsl:stylesheet>

Пробовал, думая, что это сработает, и в основном это работает, но я получаю всевозможные "отставшие".

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" encoding="UTF-8" />
  <xsl:template match="channel">
    <rss>
      <channel>
        <xsl:copy-of select="title"/>
        <xsl:copy-of select="link"/>
        <xsl:copy-of select="description"/>
    <xsl:apply-templates>
        <xsl:sort select="sort"/>
    </xsl:apply-templates>
      </channel>
    </rss>
  </xsl:template>

  <xsl:template match="item">
    <xsl:copy-of select="." />
  </xsl:template>

  <xsl:template match="label">
    <xsl:copy-of select="." />
  </xsl:template>

</xsl:stylesheet>

«Отставшие» выглядят так, когда все сказано и сделано с использованием новейшего XSL:

<rss xmlns:st="http://ww2.startribune.com/rss/modules/base/">
  <channel>
    <title>A Title</title>
    <link>http://www.mydomain.com/</link>
    <description>The Description</description>
A Title
http://www.mydomain.com/
The Description
        <label>...
    <item>...

Ответы [ 3 ]

3 голосов
/ 23 апреля 2011

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="channel">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="node()">
                <xsl:sort select="sort" data-type="number"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Выход:

<rss>
    <channel>
        <title>This is the title</title>
        <link>http://www.mydomain.com/</link>
        <description>The Description</description>
        <label>
            <title>A Label</title>
            <sort>1</sort>
        </label>
        <item>
            <title>An Item</title>
            <sort>2</sort>
        </item>
        <item>
            <title>One Item</title>
            <sort>3</sort>
        </item>
        <label>
            <title>Another Label</title>
            <sort>4</sort>
        </label>
    </channel>
</rss>

Примечание : правило идентификации. Сортировка channel потомков: NaN значения для ключа сортировки чисел идут первыми. Хотя это нормальное поведение, только в XSLT 2.0 это было явно определено, начиная с http://www.w3.org/TR/xslt20/#comparing-sort-keys:

Значения NaN для сортировки считается равным друг другу, и меньше, чем любое другое числовое значение.

РЕДАКТИРОВАТЬ : я не был уверен, но после поиска это также является частью спецификации XSLT 1.0 в ошибочных документах :

в порядке возрастания NaN предшествует всем другие числовые значения и по убыванию порядок следует за ними

3 голосов
/ 23 апреля 2011

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

В предоставляемом вами XSLT вы уже обрабатываете заголовок, ссылку и описание элементов в своем шаблоне канала.необходимо создать пустые шаблоны, чтобы поглотить их из-за вызова apply-templates в шаблоне канала.Например:

<xsl:template match="title|link|description"/>

Это должно высосать ваших "отставших".

1 голос
/ 23 апреля 2011

Чтобы избежать необходимости «жестко кодировать» имена конкретных «отставших», которые в противном случае были бы выбраны подходящим шаблоном по умолчанию, вы можете добавить собственный шаблон по умолчанию в этом случае, чтобы просто игнорировать такие узлы.

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

Это соответствует любому неспецифическому узлу, просто игнорирует его и продолжает обрабатывать дочерние узлы (так что, когда он совпадает с узлом 'rss', он может затем перейти к узлу 'канала'). Ваши конкретные совпадения шаблонов для 'channel', 'item' и 'label' будут иметь приоритет над этим.

Таким образом, если вы возьмете следующий XSLT

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

   <xsl:template match="channel">
      <rss>
         <channel>
            <xsl:copy-of select="title"/>
            <xsl:copy-of select="link"/>
            <xsl:copy-of select="description"/>
            <xsl:apply-templates>
               <xsl:sort select="sort"/>
            </xsl:apply-templates>
         </channel>
      </rss>
   </xsl:template>

   <xsl:template match="item">
      <xsl:copy-of select="."/>
   </xsl:template>

   <xsl:template match="label">
      <xsl:copy-of select="."/>
   </xsl:template>

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

И примените его к своему упрощенному XML, вы должны получить следующий вывод

<rss>
   <channel>
      <title>This is the title</title>
      <link>http://www.mydomain.com/</link>
      <description>The Description</description>
      <label>
         <title>A Label</title>
         <sort>1</sort>
      </label>
      <item>
         <title>An Item</title>
         <sort>2</sort>
      </item>
      <item>
         <title>One Item</title>
         <sort>3</sort>
      </item>
      <label>
         <title>Another Label</title>
         <sort>4</sort>
      </label>
   </channel>
</rss>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...