按子节点对XML节点进行排序,然后对不同的子节点进行排序

时间:2018-06-25 06:03:28

标签: xml xslt

我正在尝试创建一个XSLT文件,该文件将从源XML创建一个新XML,该XML将按名称对类型节点进行排序,然后对每种类型内的成员进行排序。

来源:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Ontario</members>
        <members>Quebec</members>
        <members>Alberta</members>
        <name>Provinces</name>
    </types>
    <types>
        <members>Vancouver</members>
        <members>Calgary</members>
        <members>Toronto</members>
        <members>Montreal</members>
        <name>Cities</name>
    </types>
    <version>43.0</version>
</Package>

预期输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Calgary</members>
        <members>Montreal</members>
        <members>Toronto</members>
        <members>Vancouver</members>
        <name>Cities</name>
    </types>    
    <types>
        <members>Alberta</members>
        <members>Ontario</members>
        <members>Quebec</members>
        <name>Provinces</name>
    </types>
    <version>43.0</version>
</Package>

我首先尝试按名称对类型进行排序,但似乎对我没有任何排序

XSL:

<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="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Package">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="types">
                <xsl:sort select="name"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

2 个答案:

答案 0 :(得分:0)

您的脚本失败,因为您忘记了名称空间。 例如。模板匹配Package名称空间,而您的输入Package元素是 在http://soap.sforce.com/2006/04/metadata命名空间中。

因此正确的XSLT脚本应:

  • 将此名称空间包含在stylesheet标记中,指定一个前缀(例如m),
  • 仅使用此前缀来引用标签名称。

下面有一个有效的脚本:

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

  <xsl:template match="m:Package">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="m:types">
        <xsl:sort select="m:name"/>
      </xsl:apply-templates>
      <xsl:apply-templates select="*[local-name() != 'types']"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="m:types">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="m:members">
        <xsl:sort select="."/>
      </xsl:apply-templates>
      <xsl:apply-templates select="m:name"/>
    </xsl:copy>
  </xsl:template>

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

如您所见,我添加了一个匹配types的模板,以提供 按照您的指定对members进行排序。

答案 1 :(得分:0)

<xsl:output method="xml" indent="yes"/>
    <xsl:template match="Package">
        <xsl:copy copy-namespaces="yes">
            <xsl:for-each select="types">
                <xsl:sort select="." order="descending"/>
                <types>
                    <xsl:for-each select="members">
                        <xsl:sort order="ascending"/>
                        <members>
                            <xsl:value-of select="."/>
                        </members>
                    </xsl:for-each>
                    <name>
                        <xsl:value-of select="name"/>
                    </name>
                </types>
            </xsl:for-each>
            <xsl:apply-templates select="version"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="version">
        <xsl:copy>
        <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
Check it