Xml 每个需求的奇怪XSLT

Xml 每个需求的奇怪XSLT,xml,xslt,foreach,xslt-1.0,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

我有一些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中,农场包含动物,但在报告中,动物包含农场

我已经做了几次尝试,但最近的一次尝试是:

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行。太好了

问题是,你可能已经发现了,只考虑了一个农场。因此,我最终得出以下结论:

ANIMAL pigs
myfarm    Oinker
myfarm2   Oinker
myfarm3   Oinker

ANIMAL cats
myfarm    Willie
myfarm2   Willie
myfarm3   Willie
我在想也许我需要重复农场,然后是动物,然后是农场?这有意义吗?
建议是非常受欢迎的。

因为您使用的是XSLT1.0,所以您需要使用

假设您的XML与我在下面猜测的类似(如果您使用示例XML更新问题,我将更新此答案),xsl:key应该使用
动物的子元素名

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>

奥克
威利
厚颜无耻的
绒毛
卷曲的
埃尔维斯
XSLT1.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)


动物
猪
我的农场
奥克
我的农场2
厚颜无耻的
我的农场3
卷曲的
动物
猫
我的农场
威利
我的农场2
绒毛
我的农场3
埃尔维斯

我想我现在有了一个可用的版本,但就像轮胎一样,“她不漂亮”。。。我在动物上循环(获取主表),然后在农场上循环(获取行),然后再循环动物(过滤掉不在此表中的动物)。我将内心的动物(听起来像禅,不是吗?)与外在的动物进行比较。如果匹配,则打印该行。很好,但没有达到我通常的优雅标准。。。从好的方面来说,我认为它可以聚合一般情况。XSLT的哪个版本?这是一个分组问题,根据您使用的XSLT版本,分组的处理方式通常有所不同。此外,如果问题中的输入被更新为XML而不是XML的树表示形式,这将非常有用。(输出也应该是您真正想要实现的内容(可能是HTML表?)。XSLT 1.0-我查看了分组等,但看起来不太有希望。我会加入更多XML风格的东西哇,谢谢,这很有帮助。我甚至不知道这是可能的。先生,我非常感谢您的回复!我的XML实际上是一个非常不同的例子——我只是用农场动物的例子来说明。你的解释很完美。我刚试过你的回答,看起来很完美。我对您正在使用的一些东西不太熟悉—模板、本地名称等,但您为我提供了一个学习XSLT的绝佳场所。再次感谢你,先生,你做了一件非常好的事情……也许你能描述一下这句话的意思?管道、钥匙和星号?xsl:for each select=“farms/farm/animals/*[count(.| key('animals',local-name())[1])=1]我在你参考的页面中看到了一些类似的代码。但没有真正解释。还在阅读-大量的理解!我像XSLT 101,这就像是研究生级别!顺便说一句,这是我正在处理的现实世界问题,不是家庭作业辅助。我现在唯一的课程是区块链。@Spyder-这是在计算两者之间的联盟n当前元素和键中的第一项。本质上,它只是选择键中的第一项。它也可以像
select=“farms/farm/animals/*[generate-id()=generate-id(key('animals',local-name())[1])那样编写“
。链接到Jeni Tennison的网页上的MuniCn分组做了很好的解释它的工作。@ Syder--也请考虑通过点击旁边的复选标记接受这个答案。