开发者

Reordering xml elements using XSLT

I have the following xml snippet which appears in开发者_如何学编程 many many places, but the order of which the TYPE element appears are random. Also, there is no guarentee that ALL Types will be available e.g. some snippets might have Visio and/or Outlook or any other nodes missing:

<Applications>
    <Type Name="Word">
    <Type Name="Excel">
    <Type Name="PowerPoint">
    <Type Name="Visio">
    <Type Name="Outlook">
</Applications>

I want to reorder the Type element so that should Type Excel exists, it will always be at the top of the list, and so on:

if EXCEL exists, 
place TYPE Excel at the top.
if WORD exists,
place TYPE Word next,
.
.
.

I have tried with xsl:copy, a couple of xsl:if and then apply the specific templates, also xsl:whens. Unfortunately none of which worked for me. I had a look at another post on reordering xml node elements, and that didn't seem like what I wanted (it used xsl:call-templates, which I don't have).

I have something that started off like the following, and I'm thinking that I need to add the manipulation code above to the bottom of this:

XML Updated

<xsl:template match="Applications">
    <xsl:element name="Applications">
        <xsl:element name="Type">
            <xsl:attribute name="Name">PowerPoint</xsl:attribute>
        </xsl:element>
        <xsl:element name="Type">
            <xsl:attribute name="Name">Outlook</xsl:attribute>
        </xsl:element>
        <xsl:apply-templates>
            <xsl:sort select="string-length(substring-before(';Excel;PowerPoint;Outlook;Word;Visio',@Name))"/>
        </xsl:apply-templates>
    </xsl:element>
</xsl:template>

Wanted:

<Applications>
    <Type Name="Excel">
    <Type Name="PowerPoint">
    <Type Name="Outlook">
    <Type Name="Word">
    <Type Name="Visio">
</Applications>

But gotten:

<Applications>
    <Type Name="PowerPoint">
    <Type Name="Outlook">
    <Type Name="Excel">
    <Type Name="Word">
    <Type Name="Visio">
</Applications>

Appreciate help on getting this thing to work... TIA.


Look into the <xsl:sort> instruction, which is used as a child of the <xsl:apply-templates> or <xsl:for-each> instructions.

If you want something sorted in a natural order (e.g. numerically or alphabetically) it's fairly easy, just specify <xsl:sort select="@Name">, for example.

If you want a custom sort order, there's a number of options, but if your list isn't huge then try this:

<xsl:sort select="number-format(string-length(substring-before(
   ';Excel;Word;PowerPoint;Outlook;Visio'
   ,@Name)),'000')" />

This basically takes the part of the string that comes before the string you're looking for, and sorts on the length of it, forcing three digits to handle lexographical sorting. Excel resolves to 001, Word resolves to 007, etc.

Alternatively, you could just brute-force it like this:

<xsl:template match="Application">
  <xsl:copy>
    <xsl:apply-templates select="Type[@Name='Excel']" />
    <xsl:apply-templates select="Type[@name='Word']" />
    <!-- etc.. -->
  </xsl:copy>
</xsl:template>

Any that aren't present are simply skipped, as there's nothing to apply the template to. It's simpler, but a bit more verbose.


Looks like you need this:

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

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


<xsl:template match="Applications">
  <xsl:copy>
  <xsl:copy-of select="@*"/>
  <xsl:apply-templates select="Type">
   <xsl:sort select="@Name"/>
  </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜