xsl: sort мне нужно отсортировать узлы, а также всех детей - PullRequest
0 голосов
/ 20 декабря 2018

Привет всем и спасибо за помощь.Мне нужно преобразовать родительский узел и все его дочерние элементы, но я не очень хорошо знаю, как работает XSLT.

После выбора узла я хочу, чтобы его дочерние элементы в алфавитном порядке (на основе атрибута «Имя» ), плюс для каждого дочернего элемента (на самом деле имеет только одного ребенка, то есть , у которого есть несколько детей ) Я должен сделать:

  1. the узлы, которые содержат подузлы перед узлами, которые имеют подузлы ;
  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>

Я пытался столько раз безрезультатно, что, наконец, я должен спросить вас.Спасибо

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Рассмотрим несколько <xsl:sort> внутри <xsl:for-each>, а затем перенесите атрибуты родительского Address узла.Кроме того, используйте substring-before для получения цифр перед первым периодом в IP-адресах, которые являются критериями сортировки (а не полной длины цифр).

Примечание: ниже пропускаются шаблоны, отсутствующие в вашем текущемXML: PolicyItems , Предопределено , PortAliases .

<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 Демо

0 голосов
/ 20 декабря 2018

Я предполагаю, что вы можете использовать XSLT-2.0, потому что тег версии xsl:stylesheet указывает на это.

Вы можете достичь своей цели, используя функцию сортировки XSLT-2.0 (здесь: sort:IPV4sorting), который имеет свое собственное пространство имен (здесь: xmlns:sort="http://www.sort.ns").

Собрав это вместе, вы получите следующую (частичную) таблицу стилей.Вам нужно только заменить шаблон 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>
...

Этот код создает 12-значное значение ключа (4 * 3 = 12) с xsl:analyze-string из адреса IPv4, который являетсяиспользуется в качестве ключа сортировки в функции сортировки.Он дважды вызывает xsl:apply-templates, чтобы обрабатывать адреса IPv6 не так, как адреса IPv4.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...