Сортировка по атрибуту, собранному из списка литературы - PullRequest
0 голосов
/ 10 сентября 2018

Я пытаюсь отсортировать список категоризированных элементов XML, используя XSLT 2.0. Каждый элемент имеет уникальный идентификатор, и категоризация определена в другом списке, содержащем эти и другие элементы. Вот пример исходного XML-документа. Я хочу отсортировать раздел / Atlas / VisitedCities. Должен быть отсортирован по региону мира и дате посещения:

<?xml version="1.0" encoding="UTF-8"?>
<Atlas>
    <Cities>
        <City id="1" worldPart="Africa">
            <Name>Luxor</Name>
            <Founded>-3200</Founded>
            <Location>Egypt</Location>
        </City>
        <City id="2" worldPart="Africa">
            <Name>Tripoli</Name>
            <Founded>-700</Founded>
            <Location>Libya</Location>
        </City>
        <City id="3" worldPart="Americas">
            <Name>Cholula</Name>
            <Founded>-200</Founded>
            <Location>Mexico</Location>
        </City>
        <City id="4" worldPart="Americas">
            <Name>Flores</Name>
            <Founded>-1000</Founded>
            <Location>Guatemala</Location>
        </City>
        <City id="5" worldPart="Europe">
            <Name>Argos</Name>
            <Founded>-5000</Founded>
            <Location>Greece</Location>
        </City>
        <City id="6" worldPart="Europe">
            <Name>Athens</Name>
            <Founded>-4000</Founded>
            <Location>Greece</Location>
        </City>
    </Cities>
    <VisitedCities lastUpdate="2018-09-10">
        <VisitedCity cityID="6">
            <Date>1883-08-26</Date>
            <Visitor>Dora</Visitor>
        </VisitedCity>
        <VisitedCity cityID="3">
            <Date>1907-01-02</Date>
            <Visitor>Nemo</Visitor>
        </VisitedCity>
        <VisitedCity cityID="4">
            <Date>1940-02-08</Date>
            <Visitor>Jimenez</Visitor>
        </VisitedCity>
        <VisitedCity cityID="2">
            <Date>1886-06-10</Date>
            <Visitor>James T. Kirk</Visitor>
        </VisitedCity>
    </VisitedCities>
</Atlas>

Требуемый вывод:

<?xml version="1.0" encoding="UTF-8"?>
<Atlas>
    <Cities>
        <City id="1" worldPart="Africa">
            <Name>Luxor</Name>
            <Founded>-3200</Founded>
            <Location>Egypt</Location>
        </City>
        <City id="2" worldPart="Africa">
            <Name>Tripoli</Name>
            <Founded>-700</Founded>
            <Location>Libya</Location>
        </City>
        <City id="3" worldPart="Americas">
            <Name>Cholula</Name>
            <Founded>-200</Founded>
            <Location>Mexico</Location>
        </City>
        <City id="4" worldPart="Americas">
            <Name>Flores</Name>
            <Founded>-1000</Founded>
            <Location>Guatemala</Location>
        </City>
        <City id="5" worldPart="Europe">
            <Name>Argos</Name>
            <Founded>-5000</Founded>
            <Location>Greece</Location>
        </City>
        <City id="6" worldPart="Europe">
            <Name>Athens</Name>
            <Founded>-4000</Founded>
            <Location>Greece</Location>
        </City>
    </Cities>
    <VisitedCities lastUpdate="2018-09-10">
        <VisitedCity cityID="2">
            <Date>1886-06-10</Date>
            <Visitor>James T. Kirk</Visitor>
        </VisitedCity>
        <VisitedCity cityID="6">
            <Date>1883-08-26</Date>
            <Visitor>Dora</Visitor>
        </VisitedCity>
        <VisitedCity cityID="3">
            <Date>1907-01-02</Date>
            <Visitor>Nemo</Visitor>
        </VisitedCity>
        <VisitedCity cityID="4">
            <Date>1940-02-08</Date>
            <Visitor>Jimenez</Visitor>
        </VisitedCity>
    </VisitedCities>
</Atlas>

Таблица стилей (XSLT 2.0), с которой я борюсь, выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <!-- Format output -->
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*" />

    <!-- Copy everything that does not match later templates. -->
    <xsl:template match="node()|@*" priority="-1">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:variable name="city.list" select="/Atlas/Cities"/>

    <xsl:variable name="sort-order" as="element()*">
        <wPart>Africa</wPart>
        <wPart>Europe</wPart>
        <wPart>Americas</wPart>
    </xsl:variable>

    <xsl:template match="/Atlas/VisitedCities">
        <xsl:variable name="city-list" select="."/>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each select="$sort-order">
                <xsl:variable name="this-wpart" select="./text()"/>
                <!-- How to select VisitedCity based on info in other list??? -->
                <xsl:apply-templates select="$city-list/VisitedCity[$city.list/City[@cityID=$city-list/VisitedCity/@cityID]/@worldPart=$this-wpart]">
                    <xsl:sort select="./Date"/>
                </xsl:apply-templates>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

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

1 Ответ

0 голосов
/ 10 сентября 2018

Может быть достаточно установить ключ для ссылки на элементы City с помощью атрибута id, а затем в выражении xsl:sort select ссылка на атрибут worldPart. Кроме того, вы можете заменить for-each в вашем заказе на континент звонком index-of() на

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="city-by-id" match="Cities/City" use="@id"/>

    <xsl:variable name="sort-order" as="element()*">
        <wPart>Africa</wPart>
        <wPart>Europe</wPart>
        <wPart>Americas</wPart>
    </xsl:variable>

  <xsl:template match="VisitedCities">
      <xsl:copy>
          <xsl:apply-templates select="VisitedCity">
              <xsl:sort select="index-of($sort-order, key('city-by-id', @cityID)/@worldPart)"/>
              <xsl:sort select="Date"/>
          </xsl:apply-templates>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / eiZQaFJ

Этот полный пример - XSLT 3, но чтобы использовать его с XSLT 2, вы просто замените объявление xsl:mode там своим шаблоном, которому вы предшествуете комментарий <!-- Copy everything that does not match later templates. -->, то есть шаблоном преобразования идентификаторов.

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