Home > Software engineering >  How can I generate a namespace for a KML file in Javascript XPath
How can I generate a namespace for a KML file in Javascript XPath

Time:09-21

I want to preface this by saying that I understand there are a lot of similar questions out there (on stack and other sites) related to this problem, but I have spent the past few hours scouring every nook and cranny of the internet and am still coming up dry.

For reference, I've examined the following sites which have provided some guidance, but generally left me more confused than I was before:
https://humanwhocodes.com/blog/2009/03/24/xpath-in-javascript-part-2/
Javascript Xpath and default namespaces
Give me an example of performing an xpath query on a KML document, from Javascript
XPath and Namespaces

Alright, onto the question. I am using Javascript and XPath to try and read a KML file. I use FileReader to get the contents of the XML file, then use the following code to try and access the XML nodes inside.

const xmlParser = new DOMParser();
const xml = xmlParser.parseFromString(contents,"text/xml");  // Contents variable contains the contents of the file (as read by FileReader)

// Read XML
if (xml.evaluate) {
// Most major browsers (except IE)
    var path = "/kml/Document/Folder[1]/Placemark/Point/coordinates";

    var evaluator = new XPathEvaluator();
    var resolver = evaluator.createNSResolver(xml.documentElement);

    var nodes = xml.evaluate(path, xml.documentElement, resolver, XPathResult.ANY_TYPE, null);
    var result = nodes.iterateNext();
    while (result) {
        console.log(result);
        result = nodes.iterateNext();
    } 
}

My KML file begins with:

<?xml version="1.0" encoding="UTF-8"?>
    <kml xmlns="http://www.opengis.net/kml/2.2">
       <Document>
           <name>-/XDF</name>

From this I understand that the xmlns property defines the namespace. My Javascript code works as expected when I remove this property from the node (as the file no longer uses a namespace), which leads me to believe that the issue is that I'm not defining a correct namespace for XPath to use.

The resolver variable is something that I copied from one of the sites linked above. I have tried to find a proper reference to how to generate a namespace resolver but cannot find something which works with my KML file.

Is anyone with more experience in this area able to point me in the right direction to generating a namespace object which will allow me to read the KML file?

CodePudding user response:

Thanks to @dandavis for the prompt.

I needed to create a separate function to return the fixed namespace:

function resolver() {
    return 'http://www.opengis.net/kml/2.2';
}

and reference my XPath path with the myns: prefix to each node.

var path = "//myns:Document/myns:Folder[1]/myns:Placemark/myns:Point/myns:coordinates";

Below is the amended routine (which references the resolver function above) in case it helps anyone else:

const xmlParser = new DOMParser();
const xml = xmlParser.parseFromString(contents,"text/xml");

// Read XML
if (xml.evaluate) {
    // Most major browsers (except IE)
    var path = "//myns:Document/myns:Folder[1]/myns:Placemark/myns:Point/myns:coordinates";

    var nodes = xml.evaluate(path, xml.documentElement, resolver, XPathResult.ANY_TYPE, null);
    var result = nodes.iterateNext();
    while (result) {
        console.log(result);
        result = nodes.iterateNext();
    } 
}

CodePudding user response:

With XPath 2 and later as supported by Saxon-JS 2 (https://www.saxonica.com/saxon-js/documentation/index.html#!api/xpathEvaluate) you can keep your XPath paths to elements compact and prefix-less by declaring a default namespaces for the XPath evaluation

var path = '//Document/Folder[1]/Placemark/Point/coordinates';

var result = SaxonJS.XPath.evaluate(path, xml, { xpathDefaultNamespace : 'http://www.opengis.net/kml/2.2' });

console.log(result);
  • Related