奇怪的XSLT for-each要求

时间:2018-02-06 14:13:12

标签: xml xslt foreach xslt-1.0

我有一些类似的XML:

farms myfarm
    animals
       pigs
         name Oinker
       cats
         name Willy
farms myfarm2
    animals
       pigs
         name Cheeky
       cats
         name Fuzz
farms myfarm3
    animals
       pigs
         name Curly
       cats
          name Elvis

每只动物下面都有很多标签。在一般情况下,动物可能因农场而异,但就我而言,它们并非如此。所有农场都有相同的动物。因此,我可以从任何农场获得一群动物(猫和猪),尽管更通用的解决方案是聚集来自所有农场的动物。

我想生成一个相反结构的报告,如:

ANIMAL pigs
myfarm  Oinker
myfarm2 Cheeky
myfarm3 Curly

ANIMAL cats
myfarm Willy
myfarm2 Fuzz
myfarm3  Elvis

所以在XML中,FARMS包含ANIMALS,但在报告中,ANIMALS包含FARMS。

我做了几次尝试,但最近的尝试是这样的:

xsl:for-each select="/farms[1]/animals"
xsl:variable name="animali" select="."

xsl:for-each select="farms"
 .
 .
td xsl select="$animali/name" /td

这实际上接近一个解决方案,因为如果我有3个农场,每个有2只动物,我最终得到2个表,每个3行。完美!

问题是你可能发现的,只考虑了Farm#1。所以我最终得到了:

ANIMAL pigs
myfarm    Oinker
myfarm2   Oinker
myfarm3   Oinker

ANIMAL cats
myfarm    Willie
myfarm2   Willie
myfarm3   Willie

我想也许我需要迭代FARMS,然后是动物,然后是农场?如果这有道理?

非常欢迎提供建议。

1 个答案:

答案 0 :(得分:1)

由于您使用的是XSLT 1.0,因此您需要使用Muenchian Grouping

假设您的XML与我在下面猜到的一样(如果您使用示例XML更新问题,我将更新此答案),xsl:key应使用animals的子元素名称。< / p>

XML输入

<farms>
    <farm id="myfarm">
        <animals>
            <pigs>
                <name>Oinker</name>
            </pigs>
            <cats>
                <name>Willy</name>
            </cats>     
        </animals>
    </farm>
    <farm id="myfarm2">
        <animals>
            <pigs>
                <name>Cheeky</name>
            </pigs>
            <cats>
                <name>Fuzz</name>
            </cats>     
        </animals>
    </farm>         
    <farm id="myfarm3">
        <animals>
            <pigs>
                <name>Curly</name>
            </pigs>
            <cats>
                <name>Elvis</name>
            </cats>
        </animals>
    </farm>
</farms>

XSLT 1.0

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

  <xsl:key name="animals" match="animals/*" use="local-name()"/>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:for-each 
          select="farms/farm/animals/*[count(.|key('animals',local-name())[1])=1]">
          <table>
            <thead>
              <tr>
                <th>ANIMAL</th>
                <th><xsl:value-of select="local-name()"/></th>
              </tr>
            </thead>
            <tbody>
              <xsl:for-each select="key('animals',local-name())">
                <xsl:sort select="ancestor::farm/@id" data-type="text"/>
                <tr>
                  <td><xsl:value-of select="ancestor::farm/@id"/></td>
                  <td><xsl:value-of select="name"/></td>
                </tr>
              </xsl:for-each>
            </tbody>
          </table>
        </xsl:for-each>        
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

输出(点击“运行代码段”查看呈现的HTML)

<html>
   <body>
      <table>
         <thead>
            <tr>
               <th>ANIMAL</th>
               <th>pigs</th>
            </tr>
         </thead>
         <tbody>
            <tr>
               <td>myfarm</td>
               <td>Oinker</td>
            </tr>
            <tr>
               <td>myfarm2</td>
               <td>Cheeky</td>
            </tr>
            <tr>
               <td>myfarm3</td>
               <td>Curly</td>
            </tr>
         </tbody>
      </table>
      <table>
         <thead>
            <tr>
               <th>ANIMAL</th>
               <th>cats</th>
            </tr>
         </thead>
         <tbody>
            <tr>
               <td>myfarm</td>
               <td>Willy</td>
            </tr>
            <tr>
               <td>myfarm2</td>
               <td>Fuzz</td>
            </tr>
            <tr>
               <td>myfarm3</td>
               <td>Elvis</td>
            </tr>
         </tbody>
      </table>
   </body>
</html>