XSLT按标记名称和属性值排序

时间:2011-05-11 08:59:14

标签: xslt sorting

我是XSLT的菜鸟,所以请原谅我的无知...... 我正在尝试按属性值和标记名称对简单的XML文件进行排序,但我很难访问属性的值。 这是一个完整的例子:

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

预期结果是:

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

我试图解决这个问题:

<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>

这显然根本不起作用......

在上面的示例中,我想按属性值对 b 标记进行排序,但正如您所看到的, d 标记未按属性值排序,因为它是另一个标记名称...

我想知道这是否可以使用XSLT ... 你有什么想法吗?

提前致谢。

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

我尝试了andyb解决方案似乎工作正常并且看起来很简单,但我对此解决方案有另一个问题。

假设我有这个XML:

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

我为 b 标记添加了一个可选参数。 应用andyb解决方案将忽略可选参数,因为它在模板中不匹配。结果如下:

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

而不是我期望的以下内容:

<a>
    <b attribute="b"></b>
    <b attribute="e" optionalAttr="fg"></b>
    <c></c>
    <d attribute="a"></d>
</a>
你知道吗? 提前谢谢。

3 个答案:

答案 0 :(得分:7)

您可以使用多个xsl:sort说明,例如:

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

由于默认数据类型为“text”且默认订单为“升序”,因此会提供所需的输出。

修改

这很奇怪,因为对于以下XML:

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

和上面的XSL,我得到了这个结果:

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

这包括所需的可选属性,但顺序与编辑的问题中的XML不同(<c></c>处于不同的位置)。

答案 1 :(得分:7)

此XSLT 2.0转换按元素名称和多个属性名称和值进行排序

<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>

应用于此XML文档(提供的文档,但添加了多个属性):

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

生成正确排序的结果

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

答案 2 :(得分:1)

我刚看到这个问题,因为我是xpath的新手,XSL认为我会试一试。

我似乎想出了一个完全不同的解决方案。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
    <xsl:copy>
        <xsl:apply-templates select="* | @*">
            <xsl:sort select="not(@*)" order="ascending" data-type="number"/>
            <xsl:sort select="@*"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>
<xsl:template match="*/@*">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="text()[not(string-length(normalize-space()))]"/>
<xsl:template match="*/text()[normalize-space()]">
    <xsl:value-of select="normalize-space()"/>
</xsl:template>

这取决于您希望如何订购属性......

示例1:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b attribute="e" ></b>
    <b attribute="b" ></b>
    <c></c>
    <d attribute="a"></d>
</a>

结果1

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

示例2

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b attribute="e" ></b>
    <b attribute="b" optionalAttr="fg"></b>
    <c></c>
    <d attribute="a"></d>
</a>

结果2

<?xml version="1.0" encoding="utf-8"?>
<a>
  <d attribute="a" />
  <b attribute="b" optionalAttr="fg" />
  <b attribute="e" />
  <c />
</a>

只是想知道是否有人可以看到这种方法有什么问题?

先谢谢你