问题
I have a KML file with country borders
<Document>
...
<Folder>
<name>Countries</name>
<Style>
<ListStyle>
<listItemType>checkHideChildren</listItemType>
<bgColor>00ffffff</bgColor>
<maxSnippetLines>2</maxSnippetLines>
</ListStyle>
</Style>
<Folder>
<name>Labels</name>
<Placemark>
<name>Angola</name>
<styleUrl>#NoneIconStyle</styleUrl>
<Point>
<coordinates>17.5379654426636,-12.2994772211426,0</coordinates>
</Point>
</Placemark>
... ignore these
<Folder>
<name>A -</name>
<Placemark>
<name>Afghanistan</name>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
65.62729644775391,37.33319854736328,0 65.64692687988283,37.45888137817383,0 65.70137023925781,37.53693008422852,0 65.76608276367188,37.53416061401367,0 65.7855224609375,37.56887817382813,0 66.30274963378906,37.32360076904297,0 66.53876495361328,37.36051177978516,0 66.58690643310547,37.36803817749023,0 66.66525268554688,37.33832168579102,0 66.74442291259766,37.36137008666992,0 67.02163696289063,37.37720108032227,0 67.20025634765625,37.24665069580078,0 67.22942352294922,37.19192886352539,0 67.26637268066406,37.18526077270508,0 67.42440795898438,37.23498916625977,0 67.52163696289063,37.27248001098633,0 67.55745697021484,37.21554183959961,0 67.64940643310547,37.24608993530273,0 67.77413940429689,37.20608901977539,0 67.77715301513672,37.18579864501953,0
It has every country. I want to make a separate files for each country. I want to ignore the initial 'lables' folder and move the Folder with the coordinates one up in the tree. So Afghanistan.KML would be
<?xml version="1.0" encoding="UTF-8"?>
<kml>
<Document>
<Folder>
<name>Countries</name>
<Placemark>
<name>Afghanistan</name>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
65.62729644775391,37.33319854736328,0 65.64692687988283,37.45888137817383,0 65.70137023925781,37.53693008422852,0 65.76608276367188,37.53416061401367,0 65.7855224609375,37.56887817382813,0 66.30274963378906,37.32360076904297,0 66.53876495361328,37.36051177978516,0 66.58690643310547,37.36803817749023,0 66.66525268554688,37.33832168579102,0 66.74442291259766,37.36137008666992,0 67.02163696289063,37.37720108032227,0 67.20025634765625,37.24665069580078,0 67.22942352294922,37.19192886352539,0 67.26637268066406,37.18526077270508,0 67.42440795898438,37.23498916625977,0 67.52163696289063,37.27248001098633,0 67.55745697021484,37.21554183959961,0 67.64940643310547,37.24608993530273,0 67.77413940429689,37.20608901977539,0 67.77715301513672,37.18579864501953,0
...etc
My XSLT nearly works
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*[local-name()='kml']/*[local-name()='Document']"/>
</xsl:template>
<xsl:template match="*[local-name()='kml']/*[local-name()='Document']">
<Document>
<xsl:apply-templates select="*[local-name()='Folder']"/>
</Document>
</xsl:template>
<xsl:template match="*[local-name()='Folder']">
<xsl:apply-templates select="*[local-name()='Folder' or local-name()='Placemark']"/>
</xsl:template>
<xsl:template match="*[local-name()='Placemark']">
<name>{name}</name> <!-- !! -->
<xsl:result-document method="xml" href="d:\downloads\countries\{name}.xml">-->
<xsl:apply-templates select="*[local-name()='Polygon']"/>
</xsl:result-document>
</xsl:template>
<xsl:template match="*[local-name()='Polygon']">
<Polygon>
<xsl:apply-templates select="*[local-name()='outerBoundaryIs']"/>
</Polygon>
</xsl:template>
<xsl:template match="*[local-name()='outerBoundaryIs']">
<outerBoundaryIs>
<xsl:apply-templates select="*[local-name()='LinearRing']"/>
</outerBoundaryIs>
</xsl:template>
<xsl:template match="*[local-name()='LinearRing']">
<LinearRing>
</LinearRing>
<xsl:apply-templates select="*[local-name()='coordinates']"/>
</xsl:template>
<xsl:template match="*[local-name()='coordinates']">
<coordinates>
<xsl:value-of select="."/>
</coordinates>
</xsl:template>
</xsl:stylesheet>
but I can't get the processor to recognise the 'name' and switch files (marked by <!-- !! -->
).
Is there an XSL wizard whou could help me out?
Thanks!
回答1:
The following stylesheet works with the http://www.calvert.ch/download/world-borders.kml data (note xpath-default-namespace
).
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.opengis.net/kml/2.2"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//Folder[matches(name,'[A-Z] -')]"/>
</xsl:template>
<xsl:template match="Folder">
<xsl:for-each select="Placemark">
<xsl:result-document href="{name}.xml">
<kml>
<Document>
<Folder>
<name>Countries</name>
<xsl:copy-of select="."/>
</Folder>
</Document>
</kml>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
回答2:
This gives you the desired output on your sample input;
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/kml">
<xsl:apply-templates select="Document/Folder[name/text()='Countries']/Folder[name/text()='Labels']/Folder[matches(name/text(),'[A-Z] -')]"/>
</xsl:template>
<xsl:template match="Folder">
<xsl:variable name="country" select="Placemark/name/text()"/>
<xsl:result-document href="{$country}.xml">
<kml>
<Document>
<Folder>
<name>Countries</name>
<xsl:copy-of select="Placemark"/>
</Folder>
</Document>
</kml>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
It makes a couple of assumptions...
- The document structure is as you have shown it, where the countries are actually within the
Labels
folder. - Country folders will be contained within alphabet-letter folders that match the given regular expression
回答3:
I can't get the processor to recognise the 'name' and switch files (marked by
<!-- !! -->
).
<name>{name}</name> <!-- !! -->
<xsl:result-document method="xml" href="d:\downloads\countries\{name}.xml">
I think you should better write somthing like this:
<name><xsl:value-of select="name"/></name>
<xsl:variable name="filename"
select="concat('d:\downloads\countries\',name,'.xml')" />
<xsl:result-document method="xml" href="{$filename}">
This is finally what would be more readable (on the same line of the other answers (+1)):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.opengis.net/kml/2.2"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/*/*/*/*[matches(name,'[A-Z]\s+-')]/Placemark">
<xsl:result-document href="d:\downloads\countries\{name}.xml">
<kml>
<Document>
<Folder>
<name>Countries</name>
<xsl:copy-of select="."/>
</Folder>
</Document>
</kml>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
来源:https://stackoverflow.com/questions/6846064/split-kml-into-subfiles-with-xslt-nearly-there-but-cant-get-it-to-work