【问题标题】:xsl:sort I need to sort nodes and also all childernxsl:sort 我需要对节点和所有子节点进行排序
【发布时间】:2019-05-21 01:16:27
【问题描述】:

大家好,感谢您的帮助。 我必须转换父节点和他的所有子节点,但我不太清楚 XSLT 是如何做的。

选择 节点后,我希望其子节点 按字母顺序排列(基于 “名称” em> 属性),另外,对于 的每个孩子(真的 只有一个孩子,即 ,其中有几个孩子

) 我必须这样做:

  1. 包含子节点
    节点在包含子节点的节点之前;
  2. 节点根据 "AddrStart" 属性按升序排序> 的“AddrBase” 属性。

我有这个 XML 代码:

<NetworkAliases>
  <NetAlias UID="{02A4738B-605C-4641-9705-E83ADFDAB221}" ZoneType="1" Name="comodo">
    <AddressItems>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="114.255.52.160" AddrEnd="114.255.52.175"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="123.124.255.96" AddrEnd="123.124.255.111"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="69.195.46.36" AddrEnd="255.255.6.39"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="97.107.169.84" AddrEnd="97.107.169.87"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="97.107.175.140" AddrEnd="97.107.175.143"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="199.66.200.0" AddrEnd="199.66.207.255"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="208.49.40.28" AddrEnd="208.49.40.31"/>
      </Address>
      <Address Source="2" Type="2">
        <IPV6 AddrType="4" AddrMask="48" AddrBase="2607F7A80E0A00000000000000000000"/>
      </Address>
      <Address Source="2" Type="2">
        <IPV6 AddrType="4" AddrMask="48" AddrBase="2607F7A8100900000000000000000000"/>
      </Address>
    </AddressItems>
  </NetAlias>
  <NetAlias UID="{0B9F7F4D-E23B-4D09-88F8-0CA378319316}" ZoneType="1" Name="akamai">
    <AddressItems>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="2.22.80.0" AddrEnd="2.22.95.255"/>
      </Address>
      <Address Source="2" Type="2">
        <IPV6 AddrType="4" AddrMask="48" AddrBase="2A0226F000DF00000000000000000000"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="95.100.224.0" AddrEnd="95.100.239.255"/>
      </Address>
    </AddressItems>
  </NetAlias>
</NetworkAliases>

这个 xsl(适用于其他节点,但不适用于这部分):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="no" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="PolicyItems">
        <xsl:copy>
            <xsl:apply-templates select="PolicyItem">
                <xsl:sort select="@Filename" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Predefined">
        <xsl:copy>
            <xsl:apply-templates select="PredefinedItem">
                <xsl:sort select="@Name" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="NetworkAliases">
        <xsl:copy>
            <xsl:apply-templates select="NetAlias">
                <xsl:sort select="@Name" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="AddressItems">
        <xsl:copy>
            <xsl:apply-templates select="Address">
                <xsl:sort select="@Type" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="PortAliases">
        <xsl:copy>
            <xsl:apply-templates select="PortAlias">
                <xsl:sort select="@Name" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <!-- To Sort also the ports -->


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

结果应该是:

<NetworkAliases>
  <NetAlias UID="{0B9F7F4D-E23B-4D09-88F8-0CA378319316}" ZoneType="1" Name="akamai">
    <AddressItems>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="2.22.80.0" AddrEnd="2.22.95.255"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="95.100.224.0" AddrEnd="95.100.239.255"/>
      </Address>
      <Address Source="2" Type="2">
        <IPV6 AddrType="4" AddrMask="48" AddrBase="2A0226F000DF00000000000000000000"/>
      </Address>
    </AddressItems>
  </NetAlias>
  <NetAlias UID="{02A4738B-605C-4641-9705-E83ADFDAB221}" ZoneType="1" Name="comodo">
    <AddressItems>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="69.195.46.36" AddrEnd="255.255.6.39"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="97.107.169.84" AddrEnd="97.107.169.87"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="97.107.175.140" AddrEnd="97.107.175.143"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="114.255.52.160" AddrEnd="114.255.52.175"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="123.124.255.96" AddrEnd="123.124.255.111"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="199.66.200.0" AddrEnd="199.66.207.255"/>
      </Address>
      <Address Source="2" Type="1">
        <IPV4 AddrType="2" AddrStart="208.49.40.28" AddrEnd="208.49.40.31"/>
      </Address>
      <Address Source="2" Type="2">
        <IPV6 AddrType="4" AddrMask="48" AddrBase="2607F7A80E0A00000000000000000000"/>
      </Address>
      <Address Source="2" Type="2">
        <IPV6 AddrType="4" AddrMask="48" AddrBase="2607F7A8100900000000000000000000"/>
      </Address>
    </AddressItems>
  </NetAlias>
</NetworkAliases>

我试了很多次都没有结果,最后我不得不问你。谢谢

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    我假设你可以使用 XSLT-2.0,因为你的xsl:stylesheet 的版本标签表明是这样的。

    您可以通过使用具有自己的命名空间(此处:xmlns:sort="http://www.sort.ns")的 XSLT-2.0 排序函数(此处:sort:IPV4sorting)来实现您的目标。

    将这些放在一起,您将获得以下(部分)样式表。您只需替换您的AddressItems 模板并添加xsl:function。您的其余代码可以保持不变。

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:sort="http://www.sort.ns">
    ...
        <xsl:function name="sort:IPV4sorting" as="xs:string">
          <xsl:param name="ipv4" as="xs:string"/>
            <xsl:variable name="numKey">
                <xsl:analyze-string select="$ipv4" regex="(\d+)\.(\d+)\.(\d+)\.(\d+)">
                    <xsl:matching-substring>
                        <xsl:value-of select="concat(format-number(xs:integer(regex-group(1)),'000'),format-number(xs:integer(regex-group(2)),'000'),format-number(xs:integer(regex-group(3)),'000'),format-number(xs:integer(regex-group(4)),'000'))" />
                    </xsl:matching-substring>
                </xsl:analyze-string>
            </xsl:variable>   
            <xsl:value-of select="$numKey" />
        </xsl:function>
    
        <xsl:template match="AddressItems">
            <xsl:copy>
                <xsl:apply-templates select="Address[IPV4]">
                    <xsl:sort select="sort:IPV4sorting(IPV4/@AddrStart)" order="ascending" />
                </xsl:apply-templates>
                <xsl:apply-templates select="Address[IPV6]">
                    <xsl:sort select="@AddrBase" order="ascending" />
                </xsl:apply-templates>
            </xsl:copy>
        </xsl:template>
    ...
    

    此代码从 IPv4 地址创建一个 12 位 键值 (4*3=12) xsl:analyze-string,用作排序函数中的排序键。它确实调用了两次xsl:apply-templates 来处理不同于 IPv4 地址的 IPv6 地址。

    【讨论】:

      【解决方案2】:

      考虑在&lt;xsl:for-each&gt; 内有多个&lt;xsl:sort&gt;,然后迁移父地址 节点的属性。此外,使用substring-before 检索 IP 地址中第一个句点之前的数字,这似乎是您的排序标准(不是数字的全长)。

      请注意:下面省略了不在您当前 XML 中的模板:PolicyItemsPredefinedPortAliases

      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
          <xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="no" indent="yes" />
          <xsl:strip-space elements="*" />
      
          <!-- IDENTITY TRANSFORM -->
          <xsl:template match="@*|node()">
              <xsl:copy>
                  <xsl:apply-templates select="@*|node()"/>
              </xsl:copy>
          </xsl:template>
      
          <xsl:template match="NetworkAliases">
              <xsl:copy>
                  <xsl:apply-templates select="NetAlias">
                      <xsl:sort select="@Name" order="ascending" />
                  </xsl:apply-templates>
              </xsl:copy>
          </xsl:template>
      
          <xsl:template match="AddressItems">
              <xsl:copy>
                  <xsl:for-each select="Address/*">
                      <xsl:sort select="@AddrType" order="ascending" data-type="number"/>                
                      <xsl:sort select="format-number(substring-before(@AddrStart, '.'), '#')" 
                                order="ascending" data-type="number"/>
                      <xsl:sort select="AddrBase" order="ascending" data-type="text"/>
      
                      <Address>
                          <xsl:copy-of select="ancestor::Address/@*"/>
                          <xsl:copy-of select="."/>
                      </Address> 
      
                  </xsl:for-each>
              </xsl:copy>
          </xsl:template>
      
      </xsl:stylesheet>
      

      XSLT 1.0 Demo

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-14
        • 2017-09-11
        • 2017-09-02
        • 1970-01-01
        • 1970-01-01
        • 2022-08-17
        • 2020-08-14
        • 2018-11-28
        相关资源
        最近更新 更多