xslt сортировать вывод xml - PullRequest
       17

xslt сортировать вывод xml

3 голосов
/ 03 октября 2011

Я пытаюсь найти решение следующей проблемы.

Я занимаюсь разработкой XSLT-преобразования (которое теперь размером около 40 КБ), которое превращает довольно сложные XML-файлы в довольно простую структуру, которая выглядит следующим образом:этот выходной XML отсортирован по Records/Record/@key значениям.Проблема в том, что мой XSLT производит этот вывод несортированным, и из-за его сложности я не могу отсортировать его там.Можно ли применить xsl:sort к выходному XML?Я знаю, что могу подготовить другое XSLT-преобразование, но в моем случае это не решение, поскольку я ограничен только одним XSLT .. Пожалуйста, помогите! ...

Ответы [ 3 ]

3 голосов
/ 03 октября 2011

Можно ли применить xsl: sort к выходному XML?

Да, многопроходная обработка возможна возможна , и особенно в XSLT 2.0 вам даже не нужно применять расширение xxx:node-set() к результату, потому что печально известный тип RTF делает больше не существует:

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

 <xsl:template match="/">
  <xsl:variable name="vPass1">
   <!--
        Put/Invoke your cirrent code here   
        to generate the following           
-->
    <Records>
      <Record key="XX3">
      </Record>
      <Record key="XX2">
      </Record>
      <Record key="XX4">
      </Record>
      <Record key="XX1">
      </Record>
    </Records>
  </xsl:variable>

  <xsl:apply-templates select="$vPass1/*"/>
 </xsl:template>

 <xsl:template match="Records">
  <Records>
   <xsl:perform-sort select="*">
    <xsl:sort select="@key"/>
   </xsl:perform-sort>
  </Records>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование выполняется для любого документа XML (не используется / игнорируется), будет получен требуемый, правильный, отсортированный результат :

<Records>
   <Record key="XX1"/>
   <Record key="XX2"/>
   <Record key="XX3"/>
   <Record key="XX4"/>
</Records>

В XSLT 1.0 это почти то же самое с дополнительным преобразованием результата из типа RTF в обычное дерево :

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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <!--
        Put/Invoke your cirrent code here   
        to generate the following           
-->
    <Records>
      <Record key="XX3">
      </Record>
      <Record key="XX2">
      </Record>
      <Record key="XX4">
      </Record>
      <Record key="XX1">
      </Record>
    </Records>
  </xsl:variable>

  <xsl:variable name="vPass1"
                select="ext:node-set($vrtfPass1)"/>

  <xsl:apply-templates select="$vPass1/*"/>
 </xsl:template>

 <xsl:template match="Records">
  <Records>
   <xsl:for-each select="*">
    <xsl:sort select="@key"/>

    <xsl:copy-of select="."/>
   </xsl:for-each>
  </Records>
 </xsl:template>
</xsl:stylesheet>
2 голосов
/ 03 октября 2011

40Kb - это много кода для одной таблицы стилей. Когда дело доходит до такого масштаба, обычно лучше разделить преобразование на конвейер меньших преобразований. Если у вас такая конвейерная архитектура, добавление шага сортировки в конце тривиально. Существует множество технологий для управления конвейером преобразований (XProc, Orbeon, xmlsh, ant, Coccoon) в зависимости от ваших требований. Преимущество конвейеризации заключается в том, что он сохраняет ваш код модульным и многократно используемым.

1 голос
/ 12 сентября 2013

Как дополнение к превосходному решению Dimitre, приведенному выше, если вы используете процессор XSLT 1.0 (например, .NET), следующее может дать вам указатель на то, как использовать набор узлов: http://www.xml.com/pub/a/2003/07/16/nodeset.html#tab.namespaces

В моем случае я был в .NET 1.1 (то есть MSXML), и решение выглядело примерно так:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:template match="/">            
        <xsl:variable name="vrtfPass1">
            <Records xmlns="">  
                    <xsl:apply-templates />
            </Records >            
        </xsl:variable>
        <xsl:variable name="vPass1" select="msxsl:node-set($vrtfPass1)"/>
        <xsl:apply-templates select="$vPass1/*" mode="sorting"/>
    </xsl:template>
    <xsl:template match="Records" mode="sorting">
        <Records>
       <xsl:for-each select="Record">
        <xsl:sort select="@key"/>
        <xsl:copy-of select="."/>
       </xsl:for-each>
      </Records>
    </xsl:template>
</xsl:stylesheet>
...