在javascript xpaths中使用xslt扩展

时间:2012-05-08 23:45:01

标签: javascript dom xpath webkit exslt

我想在使用exslt扩展的Web应用程序中使用javascript XPath,但我无法弄清楚如何执行此操作。

假装我有一个带有一些div的html doc。我想运行这个:

namespaces={'regexp':'http://exslt.org/regular-expressions'};
result = document.evaluate( 
             "//div[regexp:test(.,'$')]", 
             document, 
             function(ns){ 
                 return namespaces.hasOwnProperty(ns) ? namespaces[ns] : null;
             }, 
             XPathResult.ANY_TYPE, 
             null);

只有这会在evaluate中导致无效的XPath表达式异常。我正在使用chrome。

还有什么我需要做才能使这些东西有效吗?我在exslt.org上看到有javascript的实现,但我如何确保它们可用?我是否需要将我的javascript插入dom中的命名空间脚本元素或疯狂的东西?

更新

如果不能直接使用浏览器dom + javascript和xpath,是否可以在浏览器中使用exslt扩展编写XSLT来模拟document.evaluate(返回与xpath匹配的元素列表)?

1 个答案:

答案 0 :(得分:1)

我认为默认的浏览器XPath实现不支持EXSLT。 EXSLT页面上提到的javascript支持可能是关于如何使用in-browser.javascript提供自己的exslt函数实现。这是one example I was able to find very quickly

例如,在Firefox中,您可以拥有Saxon-B as an extension to run XSLT2.0Saxon-B has built-in support for exslt (unlike Saxon-HE), though you will likely be better off just using XSLT/XPath 2.0 features。例如,这是regular expression syntax。尽管如此,依赖于Mozilla Saxon-B扩展程序并不能帮助您使用Chrome或其他浏览器。

据说我认为你不能找到在你的XPath中使用EXSLT扩展的跨浏览器解决方案。 DOM Level 3 XPath的conformance section调用XPath 1.0支持,但未提及EXSLT。据说INVALID_EXPRESSION_ERR被抛出:

if the expression has a syntax error or otherwise is not a legal expression according to the rules of the specific XPathEvaluator or contains specialized extension functions or variables not supported by this implementation.

最后,这是Firefox的open bugzilla ticket,为他们的DOM Level 3 XPath实现开放EXSLT支持。它自2007年以来似乎一直处于新状态。机票说:

Currently Mozilla gives an exception "The expression is not a legal expression." even if a namespace resolver correctly resolving the EXSLT prefixes to the corresponding URLs is passed in。这是test case

-

如果你不介意我问,究竟你想用什么正则表达式?也许我们可以帮助您摆脱standard XPath string functions

的组合

-

更新您可以通过XSLT构建一个XPath运行器(就像您要求更新问题一样),但是它不会从源文档返回节点,它会返回看起来完全相同的新节点。 XSLT生成一个新的结果树文档,我认为没有办法让它返回对原始节点的引用。

据我所知,Mozilla(和Chrome)support XSLT不仅适用于从外部源加载的XML文档,还适用于正在显示的文档中的DOM元素。 XSLTProcessor documentation提及了tranformToFragment(),例如will only produce HTML DOM objects if the owner document is itself an HTMLDocument, or if the output method of the stylesheet is HTML

这是一个简单的XPath Runner,我构建了测试你的ides:

1)首先,您需要一个XSLT模板才能使用。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:regexp="http://exslt.org/regular-expressions" 
    extension-element-prefixes="regexp">

    <xsl:template match="/">
        <xsl:copy-of select="."/>
    </xsl:template> 
</xsl:stylesheet>

我开始使用document.implementation.createDocument APi在JavaScript中构建它,但认为加载它会更容易。 FF仍然支持document.load,而Chrome只允许您使用XHR加载内容。如果要从本地磁盘加载带有XHR的文件,则需要使用--allow-file-access-from-files启动Chrome。

2)一旦我们加载了模板,我们需要修改select指令的xsl:copy-of属性的值来运行我们需要的XPath:

function runXPath(xpath) {
    var processor = new XSLTProcessor(); 
    var xsltns = 'http://www.w3.org/1999/XSL/Transform';

    var xmlhttp = new window.XMLHttpRequest();
    xmlhttp.open("GET", "xpathrunner.xslt", false);
    xmlhttp.send(null);

    var transform = xmlhttp.responseXML.documentElement;

    var copyof = transform.getElementsByTagNameNS(xsltns, 'copy-of')[0];
    copyof.setAttribute('select', xpath);

    processor.importStylesheet(transform);          

    var body = document.getElementById('body'); // I gave my <body> an id attribute
    return processor.transformToFragment(body, document); 
}

现在可以使用以下内容运行它:

var nodes = runXPath('//div[@id]');
console.log(nodes.hasChildNodes());
if (nodes.firstChild) {
    console.log(nodes.firstChild.localName);
}

它非常适合“常规”XPath,例如//div[@id](并且无法找到//div[@not-there],但我无法让它运行regexp:test扩展功能即可。使用//div[regexp:test(string(@id), "a")]它不会出错,只返回空集。

Mozilla文档建议their XSLT processor support EXSLT。我想他们无论如何都会在幕后使用libxml / libxslt。也就是说,我无法让它在Mozilla中工作。

希望它有所帮助。

你有机会逃脱jQuery regexp吗?不太可能对您的XPath构建器实用程序有帮助,但仍然是在HTML节点上运行regexp的方法。