Сортировка нескольких элементов / атрибутов в XSL - PullRequest
0 голосов
/ 16 июня 2009

Я пытаюсь отсортировать несколько уровней данных, используя документ XSL. Я получил его на работу, но он использует кучу рекурсии. Я пытаюсь избежать этого, потому что я решил, что несколько сортировок в рамках одного узла работали. Есть ли способ изменить XSL ниже, чтобы он был менее рекурсивным? Я сортирую по USER / USERID, затем ROLE / @ name и наконец ACTIONINFO / @ actionfrom

Рабочая таблица стилей:

  <xsl:template match="/">
    <xsl:apply-templates select="USERACTIONINFO"/>
  </xsl:template>

  <xsl:template match="USERACTIONINFO">
    <xsl:copy>
      <xsl:for-each select="USER">
        <xsl:sort select="USERID"/>
        <xsl:copy>
          <xsl:copy-of select="USERID" />
          <xsl:for-each select="ROLE">
            <xsl:sort select="@name"/>
            <xsl:copy>
              <xsl:copy-of select="@name" />
              <xsl:apply-templates select="ACTIONINFO">
                <xsl:sort select="@actionfrom"/>
              </xsl:apply-templates>
            </xsl:copy>
          </xsl:for-each>
        </xsl:copy>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

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

Некоторые XML для тестирования:

 <USERACTIONINFO >
  <USER>
    <USERID>SSSUSER</USERID>
    <ROLE name="ZZ_UPD">
      <ACTIONINFO  actionfrom="ZC"  />
      <ACTIONINFO  actionfrom="AC"  />
    </ROLE>
    <ROLE name="QQ_UPD">
      <ACTIONINFO  actionfrom="AZCC11"  />
      <ACTIONINFO  actionfrom="ACC11"  />
    </ROLE>
  </USER>
  <USER>
    <USERID>AAAUSER</USERID>
    <ROLE name="PP_UPD">
      <ACTIONINFO actionfrom="ZZADBENF"  />
    </ROLE>
    <ROLE name="PP_BOEE">
      <ACTIONINFO actionfrom="BOM02"  />
    </ROLE>
    <ROLE name="PP_SS">
      <ACTIONINFO actionfrom="AZDBENF"  />
      <ACTIONINFO actionfrom="ADDBEN" />
    </ROLE>
  </USER>
</USERACTIONINFO>

Фактический ПРАВИЛЬНЫЙ выход:

   <USERACTIONINFO>
  <USER>
    <USERID>AAAUSER</USERID>
    <ROLE name="PP_BOEE">
      <ACTIONINFO actionfrom="BOM02" />
    </ROLE>
    <ROLE name="PP_SS">
      <ACTIONINFO actionfrom="ADDBEN" />
      <ACTIONINFO actionfrom="AZDBENF" />
    </ROLE>
    <ROLE name="PP_UPD">
      <ACTIONINFO actionfrom="ZZADBENF" />
    </ROLE>
  </USER>
  <USER>
    <USERID>SSSUSER</USERID>
    <ROLE name="QQ_UPD">
      <ACTIONINFO actionfrom="ACC11" />
      <ACTIONINFO actionfrom="AZCC11" />
    </ROLE>
    <ROLE name="ZZ_UPD">
      <ACTIONINFO actionfrom="AC" />
      <ACTIONINFO actionfrom="ZC" />
    </ROLE>
  </USER>
</USERACTIONINFO>

То, что я думал, что смогу сделать, но не сработало:

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

    <xsl:template match="/">
    <xsl:apply-templates select="USERACTIONINFO"/>
  </xsl:template>

  <xsl:template match="USERACTIONINFO">
    <xsl:copy>
      <xsl:apply-templates select="USER">
        <xsl:sort select="USERID"/>
        <xsl:sort select="ROLE/@name"/>
        <xsl:sort select="ROLE/ACTIONINFO/@actionfrom"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

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

Ответы [ 2 ]

2 голосов
/ 16 июня 2009

Я не уверен, почему ты так усложняешь свою жизнь. <xsl:apply-templates> делает все необходимые итерации за вас. Вы вообще не используете (или не нуждаетесь) в рекурсии для этой задачи. Просто не работайте против таких вещей, как вложение <xsl:for-each> на три уровня глубиной.

Отдельные, выделенные шаблоны легче читать и поддерживать:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <!-- in USERACTIONINFO: output USER sorted by USERID -->
  <xsl:template match="USERACTIONINFO">
    <xsl:copy>
      <xsl:apply-templates select="USER">
        <xsl:sort select="USERID" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <!-- in USER: output ROLE sorted by @name -->
  <xsl:template match="USER">
    <xsl:copy>
      <xsl:copy-of select="USERID" />
      <xsl:apply-templates select="ROLE">
        <xsl:sort select="@name" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <!-- in ROLE: output ACTIONINFO sorted by @actionfrom -->
  <xsl:template match="ROLE">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates select="ACTIONINFO">
        <xsl:sort select="@actionfrom" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <!-- output ACTIONINFO verbatim -->
  <xsl:template match="ACTIONINFO">
    <xsl:copy-of select="." />
  </xsl:template>

</xsl:stylesheet>

Результат по желанию:

<USERACTIONINFO>
  <USER>
    <USERID>AAAUSER</USERID>
    <ROLE name="PP_BOEE">
      <ACTIONINFO actionfrom="BOM02" />
    </ROLE>
    <ROLE name="PP_SS">
      <ACTIONINFO actionfrom="ADDBEN" />
      <ACTIONINFO actionfrom="AZDBENF" />
    </ROLE>
    <ROLE name="PP_UPD">
      <ACTIONINFO actionfrom="ZZADBENF" />
    </ROLE>
  </USER>
  <USER>
    <USERID>SSSUSER</USERID>
    <ROLE name="QQ_UPD">
      <ACTIONINFO actionfrom="ACC11" />
      <ACTIONINFO actionfrom="AZCC11" />
    </ROLE>
    <ROLE name="ZZ_UPD">
      <ACTIONINFO actionfrom="AC" />
      <ACTIONINFO actionfrom="ZC" />
    </ROLE>
  </USER>
</USERACTIONINFO>
0 голосов
/ 16 июня 2009

Нет, вы не можете.

Вы понимаете, что ваш код

<xsl:apply-templates select="USER">
  <xsl:sort select="USERID"/>
  <xsl:sort select="ROLE/@name"/>
</xsl:apply-templates>

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

Серьезно, когда вы применяете шаблоны к USER, вы сортируете пользователей, а не то, что внутри них. Было бы странно, если бы он действовал иначе.

Так что нет, вы должны придерживаться своего совершенно законного первого примера.

Вы можете разбить его на несколько шаблонов, сделав его несколько длиннее, но менее глубоким, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...