Search code examples
xmlxsltkmlsaxonxslt-3.0

Sorting KML placemarks alphabetically using XSLT 3.0


I am trying to sort alphabetically Placemark elements in a KML document. The document contains multiple Folder elements which I do not want to reorder. I only need to sort the Placemarks inside each Folder.

Sample input:

<?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>

Expected output:

<?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>

I have tried the following XSLT 3.0 stylesheet:

<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>

It doesn't do anything. I am trying to use XSLT 3.0 since it is the latest spec. I am using Saxon to run the transform (in case it matters):

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

If someone knows how to do this with XSLT 1.0 or 2.0, I'll take it but I'd prefer XSLT 3.0.

Cheers


Solution

  • A very basic approach would be defining a namespace on the xsl:stylesheet element and using it (the "select" expression has been wrong):

    <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>