Me Pride! Me Honor!
Arghhhhh! Once again, too many hours wasted debugging a ridiculous oversight!
Got excited about using XPath instead of DOM methods to access XML nodes after browsing through Perl & XML this morning. But then the reaper struck, and grimly. While DOM methods still worked fine, no matter how simple I made my XPath expressions, I could not get them to work from my extension javascript. Meanwhile, equivalent expressions worked just peaches-and-creamily using something like the following (replace path/to/your/file.xml and your/XPath with the path to the XML file you want to traverse and the XPath expression used in the traversal, respectively):
<html>
<head>
<script type="text/javascript">
<!--
// Evaluate an XPath expression aExpression against a given
// DOM node or Document object (aNode), returning the
// results as an array thanks wanderingstan at morethanwarm
// dot mail dot com for the initial work.
function evaluateXPath(aNode, aExpr) {
var xpe = new XPathEvaluator();
var nsResolver =
xpe.createNSResolver(aNode.ownerDocument == null ?
aNode.documentElement :
aNode.ownerDocument.documentElement);
var result = xpe.evaluate(aExpr, aNode, nsResolver,
0, null);
var found = [];
while (res = result.iterateNext())
found.push(res);
return found;
}
function getXML() {
var request = new XMLHttpRequest();
request.open('GET',
"file:///path/to/your/file.xml", false);
request.send(null);
document.write(request.responseText);
}
function test() {
var tags = evaluateXPath(document,
"/html/body/your/XPath");
var alertText = "";
for (var i = 0; i < tags.length; i++) {
alertText += tags[i].nodeName + "\n";
}
alert(alertText);
}
-->
</script>
</head>
<body>
<form>
<button type="button" onclick="test();">
XPath DEPLOY!!!
</button>
</form>
<!-- xml data island -->
<script>getXML()</script>
<!-- end data island -->
</body>
</html>
I’ve found the explanation of my woes. If the XML document uses a default namespace (instead of prefixing every tag with a namespace identifier like <html:p/>), you must provide a namepace resolving function when calling evaluate() on a document and XPath expression.
The root element of my XML file looks like this:
<dict-import-template version="0.1" xmlns="http://www.ttwhy.org/code/bookwurm/dict-import-template-0.1" template-author="Haw-Bin Chai">
So I needed to write a javascript function like the following:
const CURRENT_VERSION_NAMESPACE =
"http://www.ttwhy.org/code/bookwurm/" +
"dict-import-template-0.1";
...
function NSResolver(aPrefix) {
if(aPrefix == 'bw') {
return CURRENT_VERSION_NAMESPACE;
}
else {
// this shouldn't ever happen
return null;
}
}
call evaluate() from evaluateXPath() like so:
... var result = xpe.evaluate(aExpr, aNode, NSResolver, 0, null); ...
And actually use XPath suchly-thusly:
var results = evaluateXPath(importTemplate, "/bw:dict-import-template/*");
Whew.
<pirate>
他妈的我æ“ï¼
</pirate>
References:
http://kb.mozillazine.org/XPath
http://www.forum4designers.com/archive24-2003-12-16383.html
http://www.faqts.com/knowledge_base/view.phtml/aid/34022/fid/119