Объединяйте и сортируйте несколько файлов XML с помощью XSL - PullRequest
7 голосов
/ 06 сентября 2011

Проблема состоит в том, чтобы объединить и отсортировать несколько файлов XML с помощью XSL и вывести действительный HTML, который можно просмотреть с помощью Firefox> = 3.5 и, если возможно, IE> = 7.Ответ должен быть максимально простым (производительность не важна).

Файл a.xml

<?xml version="1.0"?>
<root>
    <tag>cc</tag>
    <tag>aa</tag>
</root>

Файл b.xml

<?xml version="1.0"?>
<root>
    <tag>xx</tag>
    <tag>bb</tag>
</root>

Индекс файла.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="merge.xslt"?>
<list>
    <entry>a.xml</entry>
    <entry>b.xml</entry>
</list>

Файл merge.xslt

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ph="http://ananas.org/2003/tips/photo">

    <xsl:output method="html"/>

    <xsl:template match="list">
        <html>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="entry">
        <xsl:for-each select="document(.)/root/tag">
            <!-- This will only sort the values of a single file -->
            <xsl:sort select="." data-type="text" order="ascending" />
            - <xsl:value-of select="."/> <br/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Текущий вывод:

  • AA

  • cc

  • bb

  • xx

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

  • aa

  • bb

  • cc

  • xx

1 Ответ

8 голосов
/ 06 сентября 2011

Решение этой проблемы - очень короткое и простое преобразование (абсолютно нет функции расширения требуются!):

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

 <xsl:template match="/*">
  <html>
   <ul>
    <xsl:apply-templates
       select="document(entry)/*/tag">
      <xsl:sort/>
    </xsl:apply-templates>
   </ul>
  </html>
 </xsl:template>

 <xsl:template match="tag">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному index.xml файлу :

<list>
    <entry>a.xml</entry>
    <entry>b.xml</entry>
</list>

желаемый, правильный результат получается :

<html>
   <ul>
      <li>aa</li>
      <li>bb</li>
      <li>cc</li>
      <li>xx</li>
   </ul>
</html>

и отображается в любом браузере как :

  • аа
  • бб
  • см
  • хх

Пояснение : В этом решении используется мощность стандартной функции XSLT document(). Как определено в Рекомендации W3C XSLT 1.0:

Когда функция документа имеет ровно один аргумент и аргумент является набором узлов, то результатом является объединение для каждого узла в набор параметров аргумента результата вызова функции документа с первый аргумент является строковым значением узла

Это объясняет эффект этого фрагмента из нашего кода :

<xsl:apply-templates
   select="document(entry)/*/tag">
  <xsl:sort/>
</xsl:apply-templates>

Здесь происходит то, что аргумент функции document() является набором узлов всех entry дочерних элементов верхнего элемента index.xml. Результатом является объединение всех узлов документа.

Поэтому

select="document(entry)/*/tag"

выделяет все элементы tag во всех документах, на которые есть ссылка в index.xml. Затем они сортируются (xsl:sort), и каждый элемент уже отсортированного нодлиста обрабатывается шаблоном, соответствующим tag.

...