简体   繁体   English

XSLT对不同父节点下的子节点进行排序

[英]XSLT sort child nodes under different parent nodes

I'm trying to sort xml with xslt but the problem is that my code only sort elements under specific node, here is a sample xml: 我正在尝试使用xslt对xml进行排序,但是问题是我的代码仅对特定节点下的元素进行了排序,这是一个示例xml:

<region name="Germany">
    <company name="Mercedes" rank="2" />
    <company name="BMW" rank="3" />
</region>
<region name="Japan">
    <company name="Toyota" rank="1" />
    <company name="Mazda" rank="4" />
</region>

I tried the folowing but it didn't work 我尝试了以下操作,但没有成功

<xsl:template match="region">
    <Companies>
        <xsl:for-each select="company">
            <xsl:sort select="@rank" />
            <xsl:call-template name="companies">
        </xsl:for-each>
    </Companies>
</xsl:template>

<xsl:template name="companies">
     <Company>
        <xsl:value-of select="@name" />
     </Company>
</xsl:template>

the output should be: 输出应为:

<Companies>
    <Company>Toyota</Company>
    <Company>Mercedes</Company>
    <Company>BMW</Company>
    <Company>Mazda</Company>
</Companies>

From the output it seems you want to sort by rank and not name. 从输出看来,您似乎要按等级而不是名称进行排序。

Regarding the sorting happening withing the node, since your template is running for each region and so the sorting is for company nodes within a region. 关于随节点进行的排序,因为您的模板正在每个区域运行,所以排序是针对一个区域内的公司节点。 You could run template for parent of region and then iterate over elements and sort by name. 您可以为区域的父级运行模板,然后遍历元素并按名称排序。 Here is the template with the matching output. 这是带有匹配输出的模板。

<xsl:template match="*[region]">
    <Companies>
        <xsl:for-each select="region/company">
            <xsl:sort select="@rank" />
            <xsl:call-template name="companies" />
        </xsl:for-each>
    </Companies>
</xsl:template>

<xsl:template name="companies">
     <Company>
        <xsl:value-of select="@name" />
     </Company>
</xsl:template> 

You haven't shown any container element for those region elements but assuming you have them inside one common container write a template matching that container (eg named root in the sample code below) and then I would simply suggest to apply-templates to the company grandchildren with an xsl:sort included based on the rank attribute. 您没有显示这些region元素的任何容器元素,但是假设您将它们包含在一个公共容器中,请编写一个与该容器匹配的模板(例如,在下面的示例代码中命名为root ),然后我建议将模板应用于company根据rank属性包含xsl:sort孙子代。

Then add a template transforming from the attribute based company input elements to a value based element and you are done: 然后添加一个模板,该模板从基于属性的company输入元素转换为基于值的元素,您将完成:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="root">
      <Companies>
          <xsl:apply-templates select="region/company">
              <xsl:sort select="xs:integer(@rank)"/>
          </xsl:apply-templates>
      </Companies>
  </xsl:template>

  <xsl:template match="company">
      <xsl:copy>
          <xsl:value-of select="@name"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94rmq6B https://xsltfiddle.liberty-development.net/94rmq6B

Matching on each region doesn't seem to make sense if you want to process them all together in a sorted way. 如果要以一种排序的方式一起处理所有region则在每个region匹配似乎没有任何意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM