使用 XSLT 3.0 按字母顺序对 KML 地标进行排序
Sorting KML placemarks alphabetically using XSLT 3.0
我正在尝试按字母顺序对 KML 文档中的地标元素进行排序。该文档包含多个我不想重新排序的 Folder 元素。我只需要对每个文件夹内的地标进行排序。
示例输入:
<?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,因为它是最新的规范。我正在使用 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。
干杯
从 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 及更高版本中,您还可以在 xsl:stylesheet
元素上设置 xpath-default-namespace="http://www.opengis.net/kml/2.2"
。
perform-sort
好像错了select和Folder/Placemark
,我觉得应该是Placemark
,但是只排序[=19=的任务] elements 可能无法按照您设置模板的方式解决。解决方案的复杂性取决于输入的可能复杂性,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。
如果 Placemark 元素都相邻则
<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>
应该足够了。
一个非常基本的方法是在 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>
我正在尝试按字母顺序对 KML 文档中的地标元素进行排序。该文档包含多个我不想重新排序的 Folder 元素。我只需要对每个文件夹内的地标进行排序。
示例输入:
<?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,因为它是最新的规范。我正在使用 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。
干杯
从 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 及更高版本中,您还可以在 xsl:stylesheet
元素上设置 xpath-default-namespace="http://www.opengis.net/kml/2.2"
。
perform-sort
好像错了select和Folder/Placemark
,我觉得应该是Placemark
,但是只排序[=19=的任务] elements 可能无法按照您设置模板的方式解决。解决方案的复杂性取决于输入的可能复杂性,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。
如果 Placemark 元素都相邻则
<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>
应该足够了。
一个非常基本的方法是在 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>