6
votes

Hi I'm trying to use the w3schools XSLT Tryit editor to transform a KML file (saved as an XML file), but I can't seem to get it working. Here is a snippet of my XML file:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
 <Document>
  <name>Bnsf RR cut</name>
  <open>1</open>
  <Style>
   <ListStyle>
    <ItemIcon>
     <href>kmzicon.png</href>
    </ItemIcon>
   </ListStyle>
  </Style>
  <Folder>
   <name>11/10/11 8:17:20 AM</name>
   <Placemark>
    <name>Track</name>
   </Placemark>
  </Folder>
  <Placemark>
   <name>Gray Mesa</name>
   <description><![CDATA[<img width="800" src="1.jpg"/>]]></description>
   <Point>
    <coordinates>-106.493097,34.446357,1692.000000</coordinates>
   </Point>
  </Placemark>
 </Document>
</kml>

And my XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
      <xsl:for-each select="Document/Placemark">
        <xsl:value-of select="name"/>
        <xsl:value-of select="description"/>
      </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

If I remove the kml tags in the XML code it works fine, but I would rather try and automate this and not have to delete code from numerous XMLs. I've tried adding "kml" to my XSLT code "/kml/Document/Placemark"> but that is not working. Thank you!

What I would like my transformed XML to look like:

 <Document> 
  <Placemark>
   <name>Gray Mesa</name>
   <description><![CDATA[<img width="800" src="1.jpg"/>]]></description>
   <Point>
    <coordinates>-106.493097,34.446357,1692.000000</coordinates>
   </Point>
  </Placemark>
 </Document>

I think this will work for my purpose.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:kml="http://www.opengis.net/kml/2.2">
   <xsl:template match="/">
  <xsl:for-each select="kml:kml/kml:Document/kml:Placemark">
     <name><xsl:value-of disable-output-escaping="yes" select="kml:name"/></name>
     <description><xsl:value-of disable-output-escaping="yes" select="kml:description"/></description>
  </xsl:for-each>
 </xsl:template>

Each name and description tag includes this however: xmlns:kml="http://www.opengis.net/kml/2.2" I can just concatenate that with an Access query though. I do get an error when I try to import into Access though. It says I need a root folder since I only have numerous name and description tags. Is there any way to add a tag using the XSL. Thank you very much. Sorry for the messy question that I keep editing.

3
I think the issue is with the namespace declarations. I don't have a solution for this issue yet, but anecdotally, if you change your loop to be "kml/Document/Placemark" and remove the namespace declarations from the <kml> element, it works. - Colin D

3 Answers

4
votes

Tim C is correct about the namespaces, but I'd like to add that XSLT is declarative language so usually when I see for-each in stylesheets it can be replace by something more fitting the language. So I would using the following code.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:kml="http://www.opengis.net/kml/2.2">
  <xsl:output method="text"/>

   <xsl:template match="/">
      <xsl:apply-templates select="kml:kml/kml:Document/kml:Placemark"/>
   </xsl:template>

   <xsl:template match="kml:Placemark">
         <xsl:value-of select="kml:name"/>
         <xsl:value-of select="kml:description"/>
   </xsl:template>

</xsl:stylesheet>
2
votes

This is because in your XML there is a default namespace

<kml xmlns="http://www.opengis.net/kml/2.2" ...

In XPath 1.0, you must specify a prefix for each namespace you want to use. A path like Document/Placemark will only select Placemark elements in no namespace.

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:kml="http://www.opengis.net/kml/2.2">
   <xsl:template match="/">
      <xsl:for-each select="kml:kml/kml:Document/kml:Placemark">
         <xsl:value-of select="kml:name"/>
         <xsl:value-of select="kml:description"/>
      </xsl:for-each>
   </xsl:template>
</xsl:stylesheet>

Also not that doing <xsl:template match="/"> matches the document element, which is not the same thing as the root element of the document kml.

Here is a good article about default namespaces: http://www.jenitennison.com/blog/node/36

Note that you might want to do this, to output the CDATA of description

<xsl:value-of select="kml:description" disable-output-escaping="yes"/>
0
votes

If its just placemarks in the Kml that your dealing with i would recommend KMLCSV Converter. (http://sourceforge.net/projects/kmlcsv/)

It wont work on lines or polygons though.

Thanks

Shane