JavaScript中的跨浏览器XPath实现

我正在寻找一个XPath库来查询FF,IE,Opera和Safari中的XML文档…并找不到一个。 你见过吗?

Google刚刚发布了Wicked Good XPath–重写了Cybozu Lab着名的JavaScript-XPath。

链接: https : //github.com/google/wicked-good-xpath

重写的版本比原来的版本小了40%,比原来的版本快了约30%。

Google的AJAXSLT开源项目非常符合规定的要求。

正如他们自己的描述那样:

“AJAXSLT是JavaScript中XSLT的一个实现,因为XSLT使用XPath, 所以它也是XPath的一个实现,可以独立于XSLT使用,这个实现有一个好处,就是XSLT可以在更多的浏览器上统一使用,而不是本地提供的。如果有必要的话,它可以扩展到更多的浏览器。AJAXSLT对于积极争取高级Web应用程序的跨浏览器兼容性的开发者来说是非常有趣的

更新 :2010年底,Michael Kay一直在使用GWT将他的Saxon XSLT 2.0处理器编译为Javascript(从而使其可用于所有5个主要浏览器)。 很快就会有一个轻量级的浏览器Saxon。

这是我用的

// xpath.js // ------------------------------------------------------------------ // // a cross-browser xpath class. // Derived form code at http://jmvidal.cse.sc.edu/talks/javascriptxml/xpathexample.html. // // Tested in Chrome, IE9, and FF6.0.2 // // Author : Dino // Created : Sun Sep 18 18:39:58 2011 // Last-saved : <2011-September-19 15:07:20> // // ------------------------------------------------------------------ /*jshint browser:true */ (function(globalScope) { 'use strict'; /** * The first argument to this constructor is the text of the XPath expression. * * If the expression uses any XML namespaces, the second argument must * be a JavaScript object that maps namespace prefixes to the URLs that define * those namespaces. The properties of this object are taken as prefixes, and * the values associated to those properties are the URLs. * * There's no way to specify a non-null default XML namespace. You need to use * prefixes in order to reference a non-null namespace in a query. * */ var expr = function(xpathText, namespaces) { var prefix; this.xpathText = xpathText; // Save the text of the expression this.namespaces = namespaces || null; // And the namespace mapping if (document.createExpression) { this.xpathExpr = true; // I tried using a compiled xpath expression, it worked on Chrome, // but it did not work on FF6.0.2. Threw various exceptions. // So I punt on "compiling" the xpath and just evaluate it. // // This flag serves only to store the result of the check. // // document.createExpression(xpathText, // // This function is passed a // // namespace prefix and returns the URL. // function(prefix) { // return namespaces[prefix]; // }); } else { // assume IE and convert the namespaces object into the // textual form that IE requires. this.namespaceString = ""; if (namespaces !== null) { for(prefix in namespaces) { // Add a space if there is already something there if (this.namespaceString.length>1) this.namespaceString += ' '; // And add the namespace this.namespaceString += 'xmlns:' + prefix + '="' + namespaces[prefix] + '"'; } } } }; /** * This is the getNodes() method of XPath.Expression. It evaluates the * XPath expression in the specified context. The context argument should * be a Document or Element object. The return value is an array * or array-like object containing the nodes that match the expression. */ expr.prototype.getNodes = function(xmlDomCtx) { var self = this, a, i, doc = xmlDomCtx.ownerDocument; // If the context doesn't have ownerDocument, it is the Document if (doc === null) doc = xmlDomCtx; if (this.xpathExpr) { // could not get a compiled XPathExpression to work in FF6 // var result = this.xpathExpr.evaluate(xmlDomCtx, // // This is the result type we want // XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, // null); var result = doc.evaluate(this.xpathText, xmlDomCtx, function(prefix) { return self.namespaces[prefix]; }, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); // Copy the results into an array. a = []; for(i = 0; i < result.snapshotLength; i++) { a.push(result.snapshotItem(i)); } return a; } else { // evaluate the expression using the IE API. try { // This is IE-specific magic to specify prefix-to-URL mapping doc.setProperty("SelectionLanguage", "XPath"); doc.setProperty("SelectionNamespaces", this.namespaceString); // In IE, the context must be an Element not a Document, // so if context is a document, use documentElement instead if (xmlDomCtx === doc) xmlDomCtx = doc.documentElement; // Now use the IE method selectNodes() to evaluate the expression return xmlDomCtx.selectNodes(this.xpathText); } catch(e2) { throw "XPath is not supported by this browser."; } } }; /** * This is the getNode() method of XPath.Expression. It evaluates the * XPath expression in the specified context and returns a single matching * node (or null if no node matches). If more than one node matches, * this method returns the first one in the document. * The implementation differs from getNodes() only in the return type. */ expr.prototype.getNode = function(xmlDomCtx) { var self = this, doc = xmlDomCtx.ownerDocument; if (doc === null) doc = xmlDomCtx; if (this.xpathExpr) { // could not get compiled "XPathExpression" to work in FF4 // var result = // this.xpathExpr.evaluate(xmlDomCtx, // // We just want the first match // XPathResult.FIRST_ORDERED_NODE_TYPE, // null); var result = doc.evaluate(this.xpathText, xmlDomCtx, function(prefix) { return self.namespaces[prefix]; }, XPathResult.FIRST_ORDERED_NODE_TYPE, null); return result.singleNodeValue; } else { try { doc.setProperty("SelectionLanguage", "XPath"); doc.setProperty("SelectionNamespaces", this.namespaceString); if (xmlDomCtx == doc) xmlDomCtx = doc.documentElement; return xmlDomCtx.selectSingleNode(this.xpathText); } catch(e) { throw "XPath is not supported by this browser."; } } }; var getNodes = function(context, xpathExpr, namespaces) { return (new globalScope.XPath.Expression(xpathExpr, namespaces)).getNodes(context); }; var getNode = function(context, xpathExpr, namespaces) { return (new globalScope.XPath.Expression(xpathExpr, namespaces)).getNode(context); }; /** * XPath is a global object, containing three members. The * Expression member is a class modelling an Xpath expression. Use * it like this: * * var xpath1 = new XPath.Expression("/kml/Document/Folder"); * var nodeList = xpath1.getNodes(xmldoc); * * var xpath2 = new XPath.Expression("/a:kml/a:Document", * { a : 'http://www.opengis.net/kml/2.2' }); * var node = xpath2.getNode(xmldoc); * * The getNodes() and getNode() methods are just utility methods for * one-time use. Example: * * var oneNode = XPath.getNode(xmldoc, '/root/favorites'); * * var nodeList = XPath.getNodes(xmldoc, '/x:derp/x:twap', { x: 'urn:0190djksj-xx'} ); * */ // place XPath into the global scope. globalScope.XPath = { Expression : expr, getNodes : getNodes, getNode : getNode }; }(this)); 

您可以使用jQuery的基本XPath插件来获取XPath查询function。

另外,您可以考虑阅读关于XPath XML处理的文章 (再次使用jQuery)

看看http://dev.abiss.gr/sarissa/项目。; 他们已经将大部分与XML相关的API迁移到IE,以及对文档对象进行评估的方法。 实际上,jQuery没有XPath处理器,它只有一个非常简单的pathselect器,如:/ a / b / c

以下是JavaScript中最新的跨浏览器实现: https : //github.com/andrejpavlovic/xpathjs

它function齐全,经过unit testing,并有很好的支持。 最酷的部分是它也支持命名空间!

您可能想要尝试使用支持跨浏览器的XPath 2.0语法的jQuery XPath插件 。

我不认为它允许临时查询,但是您可以查看Johann Burkard的XSLT jQuery插件,以获取有关如何实现XPath查询的灵感。 我在我的jQuery参考仪表板小部件中使用它,它确实是可靠的。

您可以利用每个浏览器的现有原生DOM支持。 为此,您将不得不创build自己的包装,原因是浏览器之间的差异。 你可以看看http://dotnetcaffe.blogspot.com

最好的祝福

FormFaces (JS中的XForms实现)有一个可靠的XPath引擎,可以很容易地提取和独立使用。

我想你可以在这里使用Cameron McCormack的xpath库 。 这对我来说是完美的。

另一个选项可能是LlamaLab XPath.js (尽pipe看起来有点老)