Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml 按嵌套参数分组的XSL_Xml_Xslt_Xslt 2.0 - Fatal编程技术网

Xml 按嵌套参数分组的XSL

Xml 按嵌套参数分组的XSL,xml,xslt,xslt-2.0,Xml,Xslt,Xslt 2.0,我有一个这样的XML文件 <fruits> <fruit> <name>banana</name> <country>Morocco</country> </fruit> <fruit> <name>orange</name> <country>Morocco</country> </fruit>

我有一个这样的XML文件

<fruits>
  <fruit>
    <name>banana</name>
    <country>Morocco</country>
  </fruit>
  <fruit>
    <name>orange</name>
    <country>Morocco</country>
  </fruit>
  <fruit>
    <name>grape</name>
    <country>Egypt</country>
  </fruit>
 </fruits>
这个怎么样:

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

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:for-each-group select="fruit" group-by="country">
        <country name="{country}">
          <xsl:for-each select="current-group()">
            <fruit>
              <name>
                <xsl:value-of select="name" />
              </name>
            </fruit>
          </xsl:for-each>
        </country>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

或者更干净的方法:

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

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:for-each-group select="fruit" group-by="country">
        <country name="{country}">
          <xsl:apply-templates select="current-group()" />
        </country>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="fruit/country" />

</xsl:stylesheet>

在示例输入上运行时,其中一个会产生:

<fruits>
   <country name="Morocco">
      <fruit>
         <name>banana</name>
      </fruit>
      <fruit>
         <name>orange</name>
      </fruit>
   </country>
   <country name="Egypt">
      <fruit>
         <name>grape</name>
      </fruit>
   </country>
</fruits>

香蕉
橙色
葡萄

如果您仅限于XSLT 1.0,那么有几种方法可以做到这一点:它们都不整洁。这一个查找所有在同一国家/地区之前没有同级的
元素。然后,它复制
元素,然后为其自身和具有相同国家/地区的每个后续兄弟节点复制一个新的
节点

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

  <xsl:output indent="yes"/>

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

  <xsl:template match="fruit">
    <xsl:if test="not(country = preceding-sibling::fruit/country)">
      <country>
        <xsl:attribute name="name">
          <xsl:value-of select="country"/>
        </xsl:attribute>
        <xsl:for-each select="../fruit[country=current()/country]">
          <fruit>
            <xsl:copy-of select="name" />
          </fruit>
        </xsl:for-each>
      </country>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

你很接近了-
groupby
表达式是相对于
select
ed节点的XPath,所以你只需要
groupby=“country”
,即使在XSLT1.0中,Muenchian分组也比使用
前面的同级节点进行分组好得多。
@JLRishe:我同意它更有效,但它也是(甚至更有效)不透明的和不可理解的。所以这取决于你所说的“更可取”是什么意思。你已经表明了你的观点,但否决票表明我的回答没有用。你真的准备这么说吗?这只是我的观点,但我认为使用
前面的兄弟姐妹进行分组是一种不好的做法,即使它更容易理解。你的回答也不正确。请仔细将您的输出与OP的期望输出进行比较。此外,OP明确表示需要2.0解决方案。这更接近,但仍然不正确。:)密切观察
国家
元素与
水果
元素的关系。
<fruits>
   <country name="Morocco">
      <fruit>
         <name>banana</name>
      </fruit>
      <fruit>
         <name>orange</name>
      </fruit>
   </country>
   <country name="Egypt">
      <fruit>
         <name>grape</name>
      </fruit>
   </country>
</fruits>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:output indent="yes"/>

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

  <xsl:template match="fruit">
    <xsl:if test="not(country = preceding-sibling::fruit/country)">
      <country>
        <xsl:attribute name="name">
          <xsl:value-of select="country"/>
        </xsl:attribute>
        <xsl:for-each select="../fruit[country=current()/country]">
          <fruit>
            <xsl:copy-of select="name" />
          </fruit>
        </xsl:for-each>
      </country>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<fruits>
   <country name="Morocco">
      <fruit>
         <name>banana</name>
      </fruit>
      <fruit>
         <name>orange</name>
      </fruit>
   </country>
   <country name="Egypt">
      <fruit>
         <name>grape</name>
      </fruit>
   </country>
</fruits>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:output indent="yes"/>

  <xsl:key name="fruit-by-country" match="fruit" use="country" />

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

  <xsl:template match="fruit">
    <xsl:if test="generate-id() = generate-id(key('fruit-by-country', country)[1])">
      <country>
        <xsl:attribute name="name">
          <xsl:value-of select="country"/>
        </xsl:attribute>
        <xsl:for-each select="key('fruit-by-country', country)">
          <fruit>
            <xsl:copy-of select="name" />
          </fruit>
        </xsl:for-each>
      </country>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>