Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
259 views
in Technique[技术] by (71.8m points)

xml - How to use XSL to sort elements by child element names

I would like to be able to sort some elements first by the name of some of their child elements, and then by an attribute.

Here is an example. I have simplified it from my actual requirement so hopefully that doesn't cause more confusion that it solves. The real requirement has a number of other elements as siblings to the 'Animals with their own sorting requirements but this fragment in particular is giving me grief.

Before Transformation

    <Animals>
      <Animal Value="20160.17">
        <Identifier id="1" />
        <Pig><!-- more elements inside here--></Pig>
      </Animal>
      <Animal Value="5000.40">
        <Identifier id="2" />
        <Cow><!-- more elements inside here--></Cow>
      </Animal>
      <Animal Value="63.44">
        <Identifier id="3" />
        <Pig><!-- more elements inside here--></Pig>
      </Animal>
      <Animal Value="4800.40">
        <Identifier id="4" />
        <Cow><!-- more elements inside here--></Cow>
      </Animal>
    </Animals>

Desired Transformation

I would like each Animal element sorted so that all Animals with a Cow child come first, followed by all Animals with a Pig child. Within each of those categories, they should be sorted numerically by the Animal's Value attribute.

After Transformation

    <Animals>
      <Animal Value="4800.40">
        <Identifier id="4" />
        <Cow><!-- more elements inside here--></Cow>
      </Animal>
      <Animal Value="5000.40">
        <Identifier id="2" />
        <Cow><!-- more elements inside here--></Cow>
      </Animal>
      <Animal Value="63.44">
        <Identifier id="3" />
        <Pig><!-- more elements inside here--></Pig>
      </Animal>
      <Animal Value="20160.17">
        <Identifier id="1" />
        <Pig><!-- more elements inside here--></Pig>
      </Animal>
    </Animals>

Attempt I'm pretty new at XSL and my best attempt so far doesn't seem to take the Cow/Pig elements into account. It only sorts by the Value attribute:

  <xsl:template match="Animals">
    <xsl:copy>
        <xsl:apply-templates select="Animal">
          <xsl:sort select="name(*) = 'Cow'" />
          <xsl:sort select="name(*) = 'Pig'" />
          <xsl:sort select="@Value" data-type="number" />
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

question from:https://stackoverflow.com/questions/65838432/how-to-use-xsl-to-sort-elements-by-child-element-names

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your instruction:

<xsl:sort select="name(*) = 'Cow'" />

doesn't do anything because the expression:

name(*)

returns the name of the first child element - which is "Identifier" for all Animal nodes.

Try perhaps:

<xsl:sort select="name(*[2]) = 'Cow'" order="descending"/>

(The order must be descending because alphabetically "true" comes after false".)

Alternatively, you could just apply templates separately for each category:

<xsl:template match="Animals">
    <xsl:copy>
        <xsl:apply-templates select="Animal[Cow]">
            <xsl:sort select="@Value" data-type="number" />
        </xsl:apply-templates>
        <xsl:apply-templates select="Animal[Pig]">
            <xsl:sort select="@Value" data-type="number" />
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...