Search code examples
xsltkmlgoogle-earthgmlopengis

Conflicting KML xmlns attribute from KML to XSLT


I have an XSLT which has the job of reformatting KML to GML.

<?xml version="1.0"  encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.opengis.net/gml" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" exclude-result-prefixes="kml">

    <xsl:output method="xml" indent="yes" encoding="utf-8" omit-xml-declaration="yes" />

   <!-- Removes all nodes with any empty text -->
  <xsl:template match="*[.='']"/>

  <!-- Removes all nodes with any empty attribute -->
  <xsl:template match="*[@*='']"/>

    <xsl:template match="text()"/>

    <xsl:template match="/">

      <MultiSurface>
        <surfaceMembers>
          <xsl:apply-templates />
        </surfaceMembers>
      </MultiSurface>
    </xsl:template>

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

    <xsl:template match="kml:Point">
        <!--<Point>
            <xsl:apply-templates />
        </Point>-->
    </xsl:template>

    <xsl:template match="kml:LineString">
        <!--<LineString>
            <xsl:apply-templates />
        </LineString>-->
    </xsl:template>

    <xsl:template match="kml:Polygon">
          <Polygon>
              <xsl:apply-templates />
          </Polygon>
    </xsl:template>

    <xsl:template match="kml:outerBoundaryIs">
        <exterior>
            <xsl:apply-templates />
        </exterior>
    </xsl:template>

    <xsl:template match="kml:innerBoundaryIs">
        <interior>
            <xsl:apply-templates />
        </interior>
    </xsl:template>

    <xsl:template match="kml:LinearRing">
        <LinearRing>
            <xsl:apply-templates />
        </LinearRing>
    </xsl:template>

    <xsl:template match="kml:coordinates">
        <posList>
        <!--<xsl:value-of select="translate(., ',', ' ')" />-->
        <xsl:call-template name="output-tokens">
          <xsl:with-param name="list" select="." />
        </xsl:call-template>
        </posList>
    </xsl:template>

    <xsl:template name="output-tokens">
        <xsl:param name="list" />
        <xsl:variable name="newlist" select="concat(normalize-space($list), ' ')" />
        <xsl:variable name="first" select="substring-before($newlist, ' ')" />
        <xsl:variable name="remaining" select="substring-after($newlist, ' ')" />
<!-- long, lat, alt-->
        <xsl:variable name="long" select="substring-before($first, ',')" />

        <xsl:choose>
            <xsl:when test="contains(substring-after($first, ','), ',')">
                <xsl:variable name="lat" select="substring-before(substring-after($first, ','), ',')" />
                <xsl:value-of select="concat($lat, ' ', $long, ' ')" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="lat" select="substring-after($first, ',')" />
                <xsl:value-of select="concat($lat, ' ', $long, ' ')" />
            </xsl:otherwise>
        </xsl:choose>

        <xsl:if test="$remaining">
            <xsl:call-template name="output-tokens">
                <xsl:with-param name="list" select="$remaining" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Normally our clients have given us KML files that have a kml opening tag as such:

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

And for this instance the XSLT works great to transform that KML file. However we got one today that had...

<kml xmlns="http://earth.google.com/kml/2.2">...</kml>

This does not work and I assume it is because the KMLs xmlns attribute is not set to: http://www.opengis.net/kml/2.2 or alternatively the XSLTs xmlns:kml is not set to: http://earth.google.com/kml/2.2

I tried the following but it did not work

xmlns:kml="http://www.opengis.net/kml/2.2 http://earth.google.com/kml/2.2" 

I feel the answer will be stupidly simple but I have not stumbled across it yet and I am running out of stuff to try and Google. What do you guys suggest?


Solution

  • It is important to understand that XML namespace prefixes are not inherently meaningful. They are merely a form of shorthand for namespace names, which are URIs that identify namespaces. It is the namespace name, as bound to a prefix via a namespace declaration attribute, that actually identifies the namespace and scopes names in a namespace-aware XML processor, such as an XSLT processor. As such, it does not make sense to try to bind one prefix to two alternative namespace names.

    None of this has anything to do with the location of XML schema documents. Supposing, however, that the KML 2.2 you're talking about is the one described by the schema document at http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd, its namespace name is http://www.opengis.net/kml/2.2, as is expressly specified by its schema. Instance documents are not at liberty to use a different namespace name (though they are at liberty to bind whatever namespace prefix they want to that name -- it doesn't have to be "kml").

    Bottom line: there are only two possibilities:

    1. The document provided by your client is malformed as a result of using the wrong namespace name. In this case, the best thing to do is to fix the namespace name in the client's file, or ask the client to do so. You could do that by editing it, or you could write a stylesheet to perform such a transformation. Either way, it might be a good idea to validate the resulting document against the schema to which you expect it to conform.

    2. The document provided by your client is of a different XML document type (loose sense) than you expect and are prepared to handle. In this case, the only thing to do is to request a new file of the correct type from the client.