Сортировка XML рекурсивно - сортируются только внутренние узлы - PullRequest
2 голосов
/ 18 марта 2011

Мне нужно отсортировать пример XML таким образом, чтобы сначала сортировались все пункты ShippingPoints, затем грузы в соответствии с их первой ShippingPoint и, наконец, Transports в соответствии с первой ShippingPoint в их первом Cargo. Поэтому я пытаюсь отсортировать все Транспорты по дате, когда они должны начаться.

Теперь я нашел решение, использующее рекурсию XSL, за исключением того, что только Cargos и ShippingPoints сортируются, как и ожидалось, а большинство внешних транспортных узлов - нет. Мне интересно, что я здесь делаю неправильно. Парсеры MSXML (VS2008) и Saxon дают мне абсолютно одинаковый результат.

Пример XML-кода:

<?xml version="1.0" encoding="utf-8"?>
<Transports>
    <Transport ID="1893">
        <Cargos>
            <Cargo ID="1532" >
                <ShippingPoints>
                    <ShippingPoint ID="1600" ArrivesOn="2011-04-07T12:00:00" />
                    <ShippingPoint ID="1601" ArrivesOn="2011-04-08T12:00:00" />
                </ShippingPoints>
            </Cargo>
            <Cargo ID="1532">
                <ShippingPoints>
                    <ShippingPoint ID="1601" ArrivesOn="2011-03-08T12:00:00" />
                    <ShippingPoint ID="1600" ArrivesOn="2011-02-07T12:00:00" />
                </ShippingPoints>
            </Cargo>
        </Cargos>
    </Transport>

    <Transport ID="1891" >
        <Cargos>
            <Cargo ID="1529" >
                <ShippingPoints>
                    <ShippingPoint ID="1594" ArrivesOn="2011-04-14T12:00:00" />
                    <ShippingPoint ID="1595" ArrivesOn="2011-04-04T13:00:00" />
                </ShippingPoints>
            </Cargo>
            <Cargo ID="1530" >
                <ShippingPoints>
                    <ShippingPoint ID="1597" ArrivesOn="2011-04-09T18:00:00" />
                    <ShippingPoint ID="1596" ArrivesOn="2011-04-04T12:00:00" />
                </ShippingPoints>
            </Cargo>
        </Cargos>
    </Transport>

    <Transport ID="1892">
        <Description/>
        <Cargos>
            <Cargo ID="1531" >
                <ShippingPoints>
                    <ShippingPoint ID="1599" ArrivesOn="2011-04-06T18:00:00" />
                    <ShippingPoint ID="1598" ArrivesOn="2011-04-05T12:00:00" />
                </ShippingPoints>
            </Cargo>
            <Cargo ID="1531" >
                <ShippingPoints>
                    <ShippingPoint ID="1599" ArrivesOn="2011-04-02T18:00:00" />
                    <ShippingPoint ID="1598" ArrivesOn="2011-04-03T12:00:00" />
                </ShippingPoints>
            </Cargo>
        </Cargos>
    </Transport>
</Transports>

XSLT код:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" />

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

    <xsl:template match="ShippingPoints">
        <xsl:copy>
            <xsl:apply-templates select="ShippingPoint">
                <xsl:sort select="@ArrivesOn" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Cargos">
        <xsl:copy>
            <xsl:apply-templates select="Cargo">
                <xsl:sort select="ShippingPoints/ShippingPoint[1]/@ArrivesOn" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Transports">
        <xsl:copy>
            <xsl:apply-templates select="Transport">
                <xsl:sort select="Cargos/Cargo[1]/ShippingPoints/ShippingPoint[1]/@ArrivesOn"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Ответы [ 2 ]

3 голосов
/ 18 марта 2011

Если я не понял этого, вы ищете сортировку по минимуму @ArrivesOn потомка. Самая короткая таблица стилей:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="node()">
                <xsl:sort select="min(.//@ArrivesOn/xs:dateTime(.))"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Выход:

<Transports>
    <Transport ID="1893">
        <Cargos>
            <Cargo ID="1532">
                <ShippingPoints>
                    <ShippingPoint ID="1600" ArrivesOn="2011-02-07T12:00:00"/>
                    <ShippingPoint ID="1601" ArrivesOn="2011-03-08T12:00:00"/>
                </ShippingPoints>
            </Cargo>
            <Cargo ID="1532">
                <ShippingPoints>
                    <ShippingPoint ID="1600" ArrivesOn="2011-04-07T12:00:00"/>
                    <ShippingPoint ID="1601" ArrivesOn="2011-04-08T12:00:00"/>
                </ShippingPoints>
            </Cargo>
        </Cargos>
    </Transport>
    <Transport ID="1892">
        <Description/>
        <Cargos>
            <Cargo ID="1531">
                <ShippingPoints>
                    <ShippingPoint ID="1599" ArrivesOn="2011-04-02T18:00:00"/>
                    <ShippingPoint ID="1598" ArrivesOn="2011-04-03T12:00:00"/>
                </ShippingPoints>
            </Cargo>
            <Cargo ID="1531">
                <ShippingPoints>
                    <ShippingPoint ID="1598" ArrivesOn="2011-04-05T12:00:00"/>
                    <ShippingPoint ID="1599" ArrivesOn="2011-04-06T18:00:00"/>
                </ShippingPoints>
            </Cargo>
        </Cargos>
    </Transport>
    <Transport ID="1891">
        <Cargos>
            <Cargo ID="1530">
                <ShippingPoints>
                    <ShippingPoint ID="1596" ArrivesOn="2011-04-04T12:00:00"/>
                    <ShippingPoint ID="1597" ArrivesOn="2011-04-09T18:00:00"/>
                </ShippingPoints>
            </Cargo>
            <Cargo ID="1529">
                <ShippingPoints>
                    <ShippingPoint ID="1595" ArrivesOn="2011-04-04T13:00:00"/>
                    <ShippingPoint ID="1594" ArrivesOn="2011-04-14T12:00:00"/>
                </ShippingPoints>
            </Cargo>
        </Cargos>
    </Transport>
</Transports>
0 голосов
/ 18 марта 2011

Если вы хотите пошаговое преобразование, вам следует использовать режимы и переменные для хранения временных результатов, как в следующем примере XSLT 2.0:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
      <xsl:variable name="t1">
        <xsl:apply-templates mode="step1"/>
      </xsl:variable>
      <xsl:variable name="t2">
        <xsl:apply-templates select="$t1/node()" mode="step2"/>
      </xsl:variable>
      <xsl:apply-templates select="$t2/node()"/>
    </xsl:template>

    <xsl:template match="@*|node()" mode="#all">
        <xsl:copy>
            <xsl:apply-templates select="@*, node()" mode="#current"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ShippingPoints" mode="step1">
        <xsl:copy>
            <xsl:apply-templates select="ShippingPoint">
                <xsl:sort select="@ArrivesOn" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Cargos" mode="step2">
        <xsl:copy>
            <xsl:apply-templates select="Cargo">
                <xsl:sort select="ShippingPoints/ShippingPoint[1]/@ArrivesOn" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Transports">
        <xsl:copy>
            <xsl:apply-templates select="Transport">
                <xsl:sort select="Cargos/Cargo[1]/ShippingPoints/ShippingPoint[1]/@ArrivesOn"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Я думаю, что это делает то, что вы хотите с XSLT2.0 процессор.

...