как отсортировать значения с помощью XSLT? - PullRequest
3 голосов
/ 27 сентября 2011

У меня есть XML, похожий на этот:

<Test>
  <grapes>
     <a>TypeA</a>
     <b>value1</b>
  </grapes>
  <oranges>
     <a>TypeB</a>
     <b>value2</b>
  </oranges>
  <apples>
    <a>TypeA</a>
     <b>value3</b>
  </apples>
</Test>

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

Я пытаюсь отсортировать его так, чтобы результат был похож на этот:

<group type="TypeA">
  <value v="value1" />
  <value v="value3" />
</group>
<group type="TypeB">
  <value v="value2" />
</group>

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

Как должен быть структурирован мой XSL?

Ответы [ 3 ]

2 голосов
/ 28 сентября 2011

Вот гораздо более простое решение (полностью "стиль нажатия", нет <xsl:for-each>, нет вложенности, нет <xsl:variable>, нет current(), нет //, нет осей):

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

 <xsl:key name="kGoodsByType" match="/*/*" use="a"/>

 <xsl:template match=
  "/*/*[generate-id()
       =
        generate-id(key('kGoodsByType', a)[1])
       ]
  ">
     <group type="{a}">
       <xsl:apply-templates select="key('kGoodsByType', a)/b"/>
     </group>
 </xsl:template>

 <xsl:template match="b">
  <value v="{.}"/>
 </xsl:template>

 <xsl:template match="*/* | text()" priority="-1"/>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному XML-документу :

<Test>
    <grapes>
        <a>TypeA</a>
        <b>value1</b>
    </grapes>
    <oranges>
        <a>TypeB</a>
        <b>value2</b>
    </oranges>
    <apples>
        <a>TypeA</a>
        <b>value3</b>
    </apples>
</Test>

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

<group type="TypeA">
   <value v="value1"/>
   <value v="value3"/>
</group>
<group type="TypeB">
   <value v="value2"/>
</group>

Объяснение : мюнхенская группировка из /*/* с использованием в качестве ключа строковых значений их a потомков.

II.Решение XSLT 2.0 :

<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:for-each-group select="*/a" group-by=".">
   <group type="{current-grouping-key()}">
     <xsl:sequence select="current-group()/../b"/>
   </group>
  </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>

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

<group type="TypeA">
   <b>value1</b>
   <b>value3</b>
</group>
<group type="TypeB">
   <b>value2</b>
</group>

Пояснение :

  1. <xsl:for-each-group>

  2. current-group()

  3. current-grouping-key()

1 голос
/ 28 сентября 2011

XSLT 1.0:

Вы начинаете с создания уникальных групп для ваших типов, используя метод muenchian.Google это, чтобы узнать, что это такое.Тогда вам нужно просто выполнить итерацию по ним и распечатать то, что вы хотите, как вы хотите:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="types" match="a" use="text()"/>
<xsl:template match="/">
<result>
  <xsl:for-each select="//a[generate-id(.) = generate-id(key('types', text())[1])]">
    <group type="{current()/text()}">
      <xsl:for-each select="//a[text() = current()/text()]">
        <xsl:variable name="values" select="following-sibling::b | preceding-sibling::b"/>
        <xsl:for-each select="$values">
          <value v="{current()}"/>
        </xsl:for-each>
      </xsl:for-each>
    </group>
  </xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>

Вы обнаружите, что вывод идентичен тому, что вы ожидаете.

0 голосов
/ 28 сентября 2011

Мое предложение немного отличается от предложения FailedDev:

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

  <xsl:template match="/Test">
    <root>
      <xsl:for-each select="*[a != following::a]">
        <xsl:sort select="a" data-type="text" />
        <group type="{a}">
          <xsl:for-each select="/Test/*[a = current()/a]">
            <xsl:sort select="b" data-type="text" />
            <value v="{b}" />
          </xsl:for-each>
        </group>
      </xsl:for-each>
    </root>
  </xsl:template>
</xsl:stylesheet>

Внешний

<xsl:for-each select="*[a != following::a]" />

выбрать все уникальные типы, т.е. Тип A и Тип B .

<xsl:sort select="a" data-type="text" />

сортирует их по названию, убедившись, что TypeA появится над TypeB . Внутренний

<xsl:for-each select="/Test/*[a = current()/a]" />

выбирает список уникальных значений для каждого типа, т.е. для TypeA извлекаются значения value1 и value3 . Опять же, результирующий список сортируется по списку значение1 до значение3 .

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