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
736 views
in Technique[技术] by (71.8m points)

sorting - XSLT sort by tag name and attribute value

I'm a noob with XSLT, so please excuse my ignorance... I'm trying to sort a simple XML file by attribute value and tag name, but I struggle in accessing the value of the attribute. Here is a complete example:

<a>
    <b attribute="e"></b>
    <b attribute="b"></b>
    <d attribute="a"></d>
    <c></c>
</a>

And the expected result is:

<a>
    <b attribute="b"></b>
    <b attribute="e"></b>
    <c></c>
    <d attribute="a"></d>
</a>

Here is my attempt to solve this:

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

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

            <xsl:apply-templates select="node()">
                <xsl:sort select="name()"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

And this obviously don't work at all...

In the above example I want to sort the b tag by their attribute value but as you can see the d tag is not sorted by attribute value because it's another tag name...

I wonder if this is possible using XSLT... Do you have an idea?

Thanks in advance.

UPDATE----------------------

I tried andyb solution that seems to work fine and looks pretty simple, but I have another issue with this solution.

Let's say I have this XML:

<a>
    <b attribute="e" optionalAttr="fg"></b>
    <b attribute="b"></b>
    <d attribute="a"></d>
    <c></c>
</a>

I added an optional parameter for the b tag. Applying andyb solution the optional parameter will be ignored, because it is not matched in the template. Here is the result:

<a>
    <b attribute="b"></b>
    <b attribute="e"></b>
    <c></c>
    <d attribute="a"></d>
</a>

Instead of the following which is what I expect:

<a>
    <b attribute="b"></b>
    <b attribute="e" optionalAttr="fg"></b>
    <c></c>
    <d attribute="a"></d>
</a>

Do you have any idea? Thanks in advance.

See Question&Answers more detail:os

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

1 Answer

0 votes
by (71.8m points)

This XSLT 2.0 transformation performs sorting by element name and multiple attributes nameand value:

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

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

    <xsl:function name="my:attributeScore" as="xs:string">
      <xsl:param name="pThis" as="node()"/>

      <xsl:variable name="vScore">
          <xsl:for-each select="$pThis/@*">
           <xsl:sort select="name()"/>

           <xsl:value-of select="concat(name(),'+',.)"/>
          </xsl:for-each>
          <xsl:text>|</xsl:text>
      </xsl:variable>

      <xsl:sequence select="string-join($vScore, '')"/>
    </xsl:function>
</xsl:stylesheet>

when applied on this XML document (the provided one, but added multiple attributes):

<a>
    <b attribute="e" x="y"></b>
    <b attribute="e" x="x"></b>
    <b attribute="b"></b>
    <d attribute="a"></d>
    <c></c>
</a>

the correctly sorted result is produced:

<a>
   <b attribute="b"/>
   <b attribute="e" x="x"/>
   <b attribute="e" x="y"/>
   <c/>
   <d attribute="a"/>
</a>

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

...