Отдельный список значений из дочерних элементов XML с использованием XSL

У меня есть XML, как показано ниже

<?xml version="1.0" encoding="UTF-8"?>
<Set>
<Bundles>
    <BundleID>1</BundleID>
    <BundleDetails>
        <Classification>A</Classification>
        <TrackingID>34675</TrackingID>
    </BundleDetails>
    <BundleQty>12</BundleQty>
</Bundles>
<Bundles>
    <BundleID>2</BundleID>
    <BundleDetails>
        <Classification>B</Classification>
        <TrackingID>4563</TrackingID>
    </BundleDetails>
    <BundleDetails>
        <Classification>A</Classification>
        <TrackingID>4563</TrackingID>
    </BundleDetails>
    <BundleQty>34</BundleQty>
</Bundles>
<Bundles>
    <BundleID>3</BundleID>
    <BundleDetails>
        <Classification>A</Classification>
        <TrackingID>2343243</TrackingID>
    </BundleDetails>
    <BundleQty>22</BundleQty>
</Bundles>
<Bundles>
    <BundleID>4</BundleID>
    <BundleDetails>
        <Classification>A</Classification>
        <TrackingID>123231</TrackingID>
    </BundleDetails>
    <BundleDetails>
        <Classification>B</Classification>
    </BundleDetails>
    <BundleDetails>
        <Classification>B</Classification>
        <TrackingID>42342</TrackingID>
    </BundleDetails>
    <BundleQty>33</BundleQty>
</Bundles>
<Bundles>
    <BundleID>5</BundleID>
    <BundleDetails>
        <Classification>A</Classification>
        <TrackingID>123231</TrackingID>
    </BundleDetails>
    <BundleDetails>
        <Classification>A</Classification>
        <TrackingID>42342</TrackingID>
    </BundleDetails>
    <BundleDetails>
        <Classification>B</Classification>
        <TrackingID>124512</TrackingID>
    </BundleDetails>
    <BundleQty>21</BundleQty>
</Bundles>
</Set>

Мне нужно получить подробную информацию о каждом наборе/связке, как показано ниже.

Bundle# Qty  Classes
1      12      A
2      34      A,B
3      22      A
4      33     A,B
5      21     A,B

Я начал, как показано ниже, но ударил по четкому списку классов. Нужно какое-то руководство,

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

<xsl:template match="/">
  <html>
  <body>
  <p>Set Details</p>
  <table>
       <xsl:for-each select="Set/Bundles">
        <tr>
          <td><xsl:value-of select="BundleID"/></td>
          <td><xsl:value-of select="BundleQty"/></td>
          <td>--Distinct List of ./BundleDetails/Classification </td>
        </tr>
      </xsl:for-each>
   </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

Заранее оцените вашу помощь!

Благодарю вас!


person Sr7    schedule 26.10.2012    source источник


Ответы (1)


Это преобразование:

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

 <xsl:key name="kClassByValAndGrParent" match="Classification"
  use="concat(generate-id(../..),'+', .)"/>

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

 <xsl:template match="/*">
   <table border="1">
    <tr>
      <th>Bundle#</th><th>Qty</th><th>Classes</th>
    </tr>
    <xsl:apply-templates/>
   </table>
 </xsl:template>

 <xsl:template match="Bundles">
  <tr>
    <xsl:apply-templates select="*[not(self::BundleDetails)]"/>
   <td>
    <xsl:apply-templates select=
      "BundleDetails/Classification
                      [generate-id()
                      =
                       generate-id(key('kClassByValAndGrParent',
                                        concat(generate-id(../..),'+', .)
                                      )[1]
                                  )
                      ]
      "/>
   </td>
  </tr>
 </xsl:template>

 <xsl:template match="BundleID|BundleQty">
  <td><xsl:value-of select="."/></td>
 </xsl:template>

 <xsl:template match="BundleDetails"/>

 <xsl:template match="Classification">
   <xsl:if test="position() > 1">,</xsl:if>
   <xsl:value-of select="."/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

при применении к предоставленному XML-документу:

<Set>
    <Bundles>
        <BundleID>1</BundleID>
        <BundleDetails>
            <Classification>A</Classification>
            <TrackingID>34675</TrackingID>
        </BundleDetails>
        <BundleQty>12</BundleQty>
    </Bundles>
    <Bundles>
        <BundleID>2</BundleID>
        <BundleDetails>
            <Classification>B</Classification>
            <TrackingID>4563</TrackingID>
        </BundleDetails>
        <BundleDetails>
            <Classification>A</Classification>
            <TrackingID>4563</TrackingID>
        </BundleDetails>
        <BundleQty>34</BundleQty>
    </Bundles>
    <Bundles>
        <BundleID>3</BundleID>
        <BundleDetails>
            <Classification>A</Classification>
            <TrackingID>2343243</TrackingID>
        </BundleDetails>
        <BundleQty>22</BundleQty>
    </Bundles>
    <Bundles>
        <BundleID>4</BundleID>
        <BundleDetails>
            <Classification>A</Classification>
            <TrackingID>123231</TrackingID>
        </BundleDetails>
        <BundleDetails>
            <Classification>B</Classification>
        </BundleDetails>
        <BundleDetails>
            <Classification>B</Classification>
            <TrackingID>42342</TrackingID>
        </BundleDetails>
        <BundleQty>33</BundleQty>
    </Bundles>
    <Bundles>
        <BundleID>5</BundleID>
        <BundleDetails>
            <Classification>A</Classification>
            <TrackingID>123231</TrackingID>
        </BundleDetails>
        <BundleDetails>
            <Classification>A</Classification>
            <TrackingID>42342</TrackingID>
        </BundleDetails>
        <BundleDetails>
            <Classification>B</Classification>
            <TrackingID>124512</TrackingID>
        </BundleDetails>
        <BundleQty>21</BundleQty>
    </Bundles>
</Set>

выдает желаемый правильный результат:

<table border="1">
   <tr>
      <th>Bundle#</th>
      <th>Qty</th>
      <th>Classes</th>
   </tr>
   <tr>
      <td>1</td>
      <td>12</td>
      <td>A</td>
   </tr>
   <tr>
      <td>2</td>
      <td>34</td>
      <td>B,A</td>
   </tr>
   <tr>
      <td>3</td>
      <td>22</td>
      <td>A</td>
   </tr>
   <tr>
      <td>4</td>
      <td>33</td>
      <td>A,B</td>
   </tr>
   <tr>
      <td>5</td>
      <td>21</td>
      <td>A,B</td>
   </tr>
</table>

Пояснение:

  1. Надлежащее использование мюнхийского метода группировки.

  2. Правильное составное определение key, указывающее любой Classification как функцию его прародителя и его строкового значения.

person Dimitre Novatchev    schedule 26.10.2012
comment
+1 Единственное, что я бы добавил, это xsl:sort к xsl:apply-templates для Classification. - person Daniel Haley; 26.10.2012
comment
@DevNull, спасибо, и ты прав. Поскольку Bundles уже отсортированы по BundleID, я не стал добавлять какую-либо сортировку. Мы могли бы даже предположить, что может быть более одного Bundles с одним и тем же BundleID, и тогда мы должны добавить еще один уровень группировки, но это слишком далеко от реального XML-документа. - person Dimitre Novatchev; 26.10.2012