使用 XSLT 重新排序 xml 元素 [英] Reordering xml elements using XSLT

查看:27
本文介绍了使用 XSLT 重新排序 xml 元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 xml 片段,它出现在许多地方,但 TYPE 元素出现的顺序是随机的.此外,不保证所有类型都可用,例如某些片段可能缺少 Visio 和/或 Outlook 或任何其他节点:

<应用程序><类型名称="Word"><类型名称="Excel"><类型名称="PowerPoint"><类型名称="Visio"><类型名称="Outlook"></应用程序>

我想对 Type 元素重新排序,以便 Type Excel 存在时,它将始终位于列表的顶部,依此类推:

如果EXCEL存在,将 TYPE Excel 放在顶部.如果 WORD 存在,接下来放置 TYPE Word,...

我尝试过使用 xsl:copy、几个 xsl:if,然后应用特定模板,还有 xsl:whens.不幸的是,这些都不适合我.我查看了另一篇关于重新排序 xml 节点元素的帖子,这似乎不是我想要的(它使用了我没有的 xsl:call-templates).

我有一些像下面这样开始的东西,我想我需要将上面的操作代码添加到它的底部:

XML 更新

<xsl:element name="应用程序"><xsl:元素名称="类型"><xsl:attribute name="Name">PowerPoint</xsl:attribute></xsl:element><xsl:元素名称="类型"><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:模板>

通缉:

<应用程序><类型名称="Excel"><类型名称="PowerPoint"><类型名称="Outlook"><类型名称="Word"><类型名称="Visio"></应用程序>

但是得到:

<应用程序><类型名称="PowerPoint"><类型名称="Outlook"><类型名称="Excel"><类型名称="Word"><类型名称="Visio"></应用程序>

<小时>

感谢让这件事发挥作用的帮助...... TIA.

解决方案

查看 <xsl:sort> 指令,该指令用作 <xsl 的子代:apply-templates> 指令.

如果您希望以自然顺序(例如数字或字母顺序)对某些内容进行排序,这很容易,例如,只需指定 <xsl:sort select="@Name">..>

如果您想要自定义排序顺序,有多种选择,但如果您的列表不是很大,请尝试以下操作:

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

这基本上是获取您要查找的字符串之前的字符串部分,并对其长度进行排序,强制使用三位数字来处理词法排序.Excel 解析为 001,Word 解析为 007,以此类推

或者,你可以像这样暴力破解:

<xsl:copy><xsl:apply-templates select="Type[@Name='Excel']"/><xsl:apply-templates select="Type[@name='Word']"/><!-- 等等.--></xsl:copy></xsl:模板>

任何不存在的都被简单地跳过,因为没有任何东西可以应用模板.它更简单,但更冗长.

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.

这篇关于使用 XSLT 重新排序 xml 元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆