tags:

views:

61

answers:

1

Hi, I have a following XML code:

<Group>
    <GElement code="x">
        <Group>
            <GElement code="x">
                <fname>a</fname>
                <lname>b</lname>
            </GElement>
            <GElement code ="f">
                <fname>fa</fname>
            </GElement>
        </Group>
    </GElement>
    <GElement code ="f">
    </GElement>
</Group>

I would like to have the output sorted by "code" like:

<Group>
    <GElement code ="f">
    </GElement>
    <GElement code="x">
        <Group>
            <GElement code ="f">
                <fname>fa</fname>
            </GElement>
            <GElement code="x">
                <fname>a</fname>
                <lname>b</lname>
            </GElement>
        </Group>
    </GElement>
</Group>

The depth of the tree can be endless i.e. the GElement can have another Group and so on.

Any ideas?

+4  A: 

Use XslCompiledTransform (see MSDN) to apply this styleshet to your XML document:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <!-- the identity template copies everything verbatim -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
  </xsl:template>

  <!-- special template for <Group> that sorts its children -->
  <xsl:template match="Group">
    <xsl:copy>
      <xsl:copy-of select="@*" /> <!-- copy attributes, if any -->
      <xsl:apply-templates select="GElement">
        <xsl:sort select="@code" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

XML tree nesting depth can be arbitrary.

Tomalak
...yeah, something like this, was what I was thinking.
FrustratedWithFormsDesigner
@tomalak, your first xsl:template has an xsl:apply-templates end tag
DevNull
also, is `<xsl:copy-of select="@*" />` necessary? is there any difference in the output if you remove it?
DevNull
@DevNull: You're right. Corrected. No, there is no difference in the output with that particular input. But if there are attributes defined in the *actual* XML, they'll be copied. The `<xsl:copy-of select="@*" />` does not hurt or take away performance, but it makes the solution correct.
Tomalak
Thanks Tomalak. Great explanation.
DevNull
@DevNull, thinking about it, to be *really* correct, the solution would also need an `<xsl:copy-of select="node()[not(self::GElement])" />`, but I estimated that contained elements other than `<GElement>` were unlikely. This estimate could be wrong, so I add it as a comment. :)
Tomalak
Amazing solution. I tried on my huge file and it worked. Thanks a lot.
LibraRocks
@Libra: You are welcome. Glad to hear it worked. :)
Tomalak