Сортировка меток KML по алфавиту с использованием XSLT 3.0 - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь отсортировать элементы меток в алфавитном порядке в документе KML. Документ содержит несколько элементов папки, которые я не хочу менять. Мне нужно только отсортировать метки внутри каждой папки.

Пример ввода:

<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2">
  <Document>
    <name>Test</name>
    <Folder>
      <name>Zulu</name>
      <Placemark>
        <name>Bravo</name>
        <Point>
          <coordinates>
            20,30,0
          </coordinates>
        </Point>
      </Placemark>
      <Placemark>
        <name>Alfa</name>
        <Point>
          <coordinates>
            10,20,0
          </coordinates>
        </Point>
      </Placemark>
    </Folder>
    <Folder>
      <name>Yankee</name>
      <Placemark>
        <name>Delta</name>
        <Point>
          <coordinates>
            40,50,0
          </coordinates>
        </Point>
      </Placemark>
      <Placemark>
        <name>Charlie</name>
        <Point>
          <coordinates>
            30,40,0
          </coordinates>
        </Point>
      </Placemark>
    </Folder>
  </Document>
</kml>

Ожидаемый результат:

<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2">
  <Document>
    <name>Test</name>
    <Folder>
      <name>Zulu</name>
      <Placemark>
        <name>Alfa</name>
        <Point>
          <coordinates>
            10,20,0
          </coordinates>
        </Point>
      </Placemark>
      <Placemark>
        <name>Bravo</name>
        <Point>
          <coordinates>
            20,30,0
          </coordinates>
        </Point>
      </Placemark>
    </Folder>
    <Folder>
      <name>Yankee</name>
      <Placemark>
        <name>Charlie</name>
        <Point>
          <coordinates>
            30,40,0
          </coordinates>
        </Point>
      </Placemark>
      <Placemark>
        <name>Delta</name>
        <Point>
          <coordinates>
            40,50,0
          </coordinates>
        </Point>
      </Placemark>
    </Folder>
  </Document>
</kml>

Я пробовал следующую таблицу стилей XSLT 3.0:

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

  <xsl:output name="xml"/>

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

  <xsl:template match="Folder">
    <xsl:perform-sort select="Folder/Placemark">
      <xsl:sort select="name" data-type="text" order="ascending"/>
    </xsl:perform-sort>
  </xsl:template>

</xsl:stylesheet>

Это ничего не делает. Я пытаюсь использовать XSLT 3.0, так как это последняя версия c. Я использую Saxon для запуска преобразования (в случае, если это имеет значение):

java -jar Saxon-HE-10.0.jar -s:source.kml -xsl:sort.xsl -o:output.kml

Если кто-то знает, как это сделать с XSLT 1.0 или 2.0, я возьму его, но предпочел бы XSLT 3.0.

Приветствия

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

Очень базовый c подход будет определять пространство имен для элемента xsl:stylesheet и использовать его (выражение "select" было неверным):

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:kml="http://www.opengis.net/kml/2.2">
  <xsl:output name="xml"/>

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

  <xsl:template match="kml:Folder">
    <xsl:copy>
      <xsl:copy-of select="* except kml:Placemark" />
      <xsl:perform-sort select="kml:Placemark">
        <xsl:sort select="kml:name" data-type="text" order="ascending"/>
      </xsl:perform-sort>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
1 голос
/ 11 апреля 2020

Начиная с Saxon 10, например, чтобы match="Folder" соответствовало элементам в пространстве имен http://www.opengis.net/kml/2.2, вы можете использовать параметр командной строки -ns:http://www.opengis.net/kml/2.2, см. http://saxonica.com/html/documentation/using-xsl/commandline/.

Конечно, в XSLT 2 и более поздних версиях вы также можете установить xpath-default-namespace="http://www.opengis.net/kml/2.2" для элемента xsl:stylesheet.

Кажется, perform-sort имеет неправильный выбор с Folder/Placemark, я думаю это должно быть Placemark, но задача только сортировки элементов Placemark, вероятно, не решается так, как вы настроили шаблон в любом случае. Сложность решения зависит от возможной сложности ввода, могут ли элементы Placemark смешиваться с другими дочерними элементами или нет; если вы знаете, что все остальные элементы будут до потомков метки, тогда достаточно использовать

<xsl:template match="Folder">
    <xsl:copy>
        <xsl:apply-templates select="* except Placemark, sort(Placemark, (), function($p) { $p/name })"/>
    </xsl:copy>
</xsl:template>

в XSLT 3 и с Saxon 10 HE или более ранними версиями Saxon, кроме PE или EE.

Если элементы метки находятся рядом, то достаточно

<xsl:template match="Folder">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:for-each-group select="*" group-adjacent=". instance of element(Placemark)">
            <xsl:apply-templates
              select="if (current-grouping-key())
                      then sort(current-group(), (), function($p) { $p/name })
                      else current-group()"/>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

.

...