Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
XSLT按标记名和属性值排序_Xslt_Sorting - Fatal编程技术网

XSLT按标记名和属性值排序

XSLT按标记名和属性值排序,xslt,sorting,Xslt,Sorting,我是XSLT的高手,请原谅我的无知。。。 我试图按属性值和标记名对一个简单的XML文件进行排序,但在访问属性值时遇到了困难。 下面是一个完整的示例: <a> <b attribute="e"></b> <b attribute="b"></b> <d attribute="a"></d> <c></c> </a> 预期结果是: <a&

我是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。。。 你有什么想法吗

提前谢谢

更新----------------------

我尝试了andyb解决方案,它似乎工作得很好,看起来也很简单,但这个解决方案还有另一个问题

<?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>
假设我有以下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>

你知道吗? 提前感谢。

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

<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不同(
位于不同的位置)。

此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>
<a>
   <b attribute="b"/>
   <b attribute="e" x="x"/>
   <b attribute="e" x="y"/>
   <c/>
   <d attribute="a"/>
</a>

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


生成正确排序的结果

<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>
<a>
   <b attribute="b"/>
   <b attribute="e" x="x"/>
   <b attribute="e" x="y"/>
   <c/>
   <d attribute="a"/>
</a>

我刚刚看到这个问题,因为我对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>
<?xml version="1.0" encoding="utf-8"?>
<a>
  <d attribute="a" />
  <b attribute="b" optionalAttr="fg" />
  <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>
<?xml version="1.0" encoding="utf-8"?>
<a>
  <d attribute="a" />
  <b attribute="b" optionalAttr="fg" />
  <b attribute="e" />
  <c />
</a>

只是想知道是否有人认为这种方法有什么问题


高级版谢谢您的回答,我将很快检查此解决方案并通知您!只有一个问题:使用此解决方案时,当我有两个同名的标记,但其中一个具有可选属性,而另一个没有该属性时,该属性将丢失,因为没有复制(因为它不匹配),有什么想法吗?很乐意帮助:-)您可以为这个新问题添加任何示例XML吗?编辑问题是最好的,因为代码在注释中的格式不能很好。我得到了一个不同的结果。我现在只是用Firefox来测试一下。您如何测试XSL?还有,哪个输出是正确的,因为我看到的是按排序顺序排列的元素,并且您编辑的问题中的XML将它们列在不同的位置?好问题,+1。请参阅我的答案,了解一个更强大的解决方案,该解决方案基于元素名称和多属性名称和值进行排序。:)哇,这看起来不错!!我现在无法测试此解决方案,但我将很快能够测试它,并随时通知您。谢谢!我对这个样式表有意见。似乎找不到函数:ID système INCONU;木质素#24;科隆47;java.lang.NoSuchMethodException:对于扩展函数,找不到方法org.apache.xml.utils.NodeVector.attributeScore([ExpressionContext,])。智能系统;林格#22;科隆#44;java.lang.NullPointerException[致命错误]:-1:-1:文件过早结束。@reef:答案开头用粗体显示:这是XSLT 2.0解决方案。使用XSLT1.0做类似的事情是不容易的。另外,由于您刚刚开始使用XSLT,您可以得到的最佳建议是从一开始就使用XSLT2.0。哦,是的。。。我没看见,对不起。我将尝试使用能够处理XSLT2.0的Java API,我会随时通知您。@reef:很高兴知道:您可以使用Saxon 9.x XSLT2.0处理器(有一个免费的开源版本可用)。