【问题标题】:odd XSLT for-each requirement奇数 XSLT for-each 要求
【发布时间】:2018-07-16 15:15:42
【问题描述】:

我有一些类似的 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,然后是动物,然后是农场?如果这有意义吗?

欢迎提出建议。

【问题讨论】:

  • 我想我现在有一个工作版本,但就像轮胎一样,“她不漂亮”...我循环播放 ANIMALS(获取主表)然后循环播放农场(获取行)然后再次在 ANIMALS 上(过滤掉不在此表中的动物)。我比较了内在的动物(听起来是不是禅宗?)与外在的。如果它们匹配,我打印该行。有效,但达不到我通常的优雅标准...从好的方面来说,我认为它会汇总一般情况。
  • 什么版本的 XSLT?这是一个分组问题,分组的处理方式通常取决于您使用的 XSLT 版本。此外,如果您的问题中的输入更新为 XML 而不是您的 XML 的树表示,这将很有帮助。 (输出也应该是您真正想要实现的任何内容(可能是 HTML 表格?)。)
  • XSLT 1.0 - 我研究了分组等。看起来没有希望。我会加入更多 XML 风格

标签: xml xslt foreach xslt-1.0


【解决方案1】:

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

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

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>

输出(点击“Run code sn-p”查看渲染的 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>

【讨论】:

  • 哇,谢谢,这很有帮助。我什至不知道这是可能的。先生,感谢您最出色的回应!
  • 我的 XML 实际上是一个非常不同的例子——我只是用农场动物的例子来说明。你的解释很完美。我刚试过你的回复,看起来很完美。我并不真正熟悉您使用的一些东西——模板、本地名称等。但是您给了我一个完美的地方来学习很多关于 XSLT 的知识。再次感谢先生,您做了一件非常好的事..
  • 或许你能描述一下这个语句在做什么?管道、键和星号? xsl:for-each select="farms/farm/animals/*[count(.|key('animals',local-name())[1])=1] 我在您引用的页面中看到了一些类似的代码。但那里并没​​有真正解释。仍在阅读 - 大量吸收!我喜欢 XSLT 101,这就像研究生水平!顺便说一句,这是我正在研究的现实世界问题,而不是家庭作业。这些天我唯一的课程是区块链。
  • @Spyder - 所做的是计算当前元素与键中第一项之间的联合。本质上,它只是选择键中的第一项。它也可以写成select="farms/farm/animals/*[generate-id() = generate-id(key('animals',local-name())[1])]"。 Jeni Tennison 的 muenchian 分组页面的链接很好地解释了这一点。
  • @Spyder - 另外,请考虑通过单击旁边的复选标记来接受此答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-23
相关资源
最近更新 更多