从变量加载 XML 和 XSL 并在浏览器中转换

Load XML and XSL from variables and transform in the browser

下面的代码片段是我遇到的问题的最小重现。目的是通过 XSL 转换 XML 并将结果转换为变量。

注释行出现错误。我做错了什么?

更大的图景是我希望能够在浏览器中拥有 XML 文件的 URL 和 XSL 文件的 URL,并且使用 XSL 转换 XML。我从服务器管道加载的所有文件都在工作,但我收到此错误并且无法在 Google 中找到可以理解的答案。 XML 自 2014 年左右以来,客户端的转换似乎很少受到关注,所以我想知道是否有更现代的技术或插件。

我很乐意接受纯 JS 或 jquery 答案或插件。

我知道这个最小的例子不是跨浏览器的(没有针对 IE 风格的解决方案)但我应该说我确实需要一个跨浏览器的解决方案作为最终答案。

最后,我知道你可以在服务器上进行转换,这不在规范中。

这是来自控制台的错误和要点。

err=TypeError: Failed to execute 'importStylesheet' on 'XSLTProcessor': parameter 1 is not of type 'Node'.

error: { "message": "Uncaught TypeError: Failed to execute 'transformToFragment' on 'XSLTProcessor': parameter 1 is not of type 'Node'.", "filename": "https://stacksnippets.net/js", "lineno": 26, "colno": 32 }

这是导致错误的代码。

var xsltProcessor, resultDocument, xml, xsl;

var xml = '<?xml version="1.0" encoding="UTF-8"?><catalog><cd><title>Empire Burlesque</title></cd></catalog>';
var xsl = '<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/">  <h2>My CD Collection</h2>  <table border="1">    <tr bgcolor="#9acd32">      <th style="text-align:left">Title</th>      <th style="text-align:left">Artist</th>    </tr>    <xsl:for-each select="catalog/cd">    <tr>      <td><xsl:value-of select="title" /></td>    </tr>    </xsl:for-each>  </table></xsl:template></xsl:stylesheet>'


xsltProcessor = new XSLTProcessor();
try {
  xsltProcessor.importStylesheet(xsl);  // < error here !
} catch (error) {
  console.log('err=' + error);
}
resultDocument = xsltProcessor.transformToFragment(xml, document);

console.log(resultDocument);

我找到了自己的答案,所以我发帖以防将来对其他人有帮助。解决方案的关键是使用 DomParser 将 XML 和 XSL 从其字符串形式解析为文档。

灵感来自这个 SO 问题 xml 数据孤岛的解决方法 这导致了这个 MDN article about Using XML Data Islands in Mozilla 他们正在解释一个解决方法,他们做了类似于加载 HTML5 'data blocks' 的事情。

注意:如果您查看开发控制台,您可能会看到很多与 DOM 异常和跨源相关的错误。看起来这段代码与 SO 代码片段机器放在一起不舒服,但如果您将其作为脚本块剪切并粘贴到您自己的 html 中,它运行得很好,在控制台中生成令人愉悦的“#document-fragment”。

var xsltProcessor, resultDocument, xml, xsl;

var xml = '<?xml version="1.0" encoding="UTF-8"?><catalog><cd><title>Empire Burlesque</title></cd></catalog>';
var xsl = '<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/">    <xsl:for-each select="catalog/cd">      <xsl:value-of select="title" />    </xsl:for-each></xsl:template></xsl:stylesheet>';

// Secret sauce start. 
var parser = new DOMParser();
var xsl_doc = parser.parseFromString(xsl, "application/xml");
var xml_doc = parser.parseFromString(xml, "application/xml");
// end of secret sauce.

xsltProcessor = new XSLTProcessor();
try {
  xsltProcessor.importStylesheet(xsl_doc);
} catch (error) {
  console.log('err=' + error);
}
resultDocument = xsltProcessor.transformToFragment(xml_doc, document);

console.log(resultDocument);

回答这部分问题:

XML transformation at the client appears to have had little focus since around 2014 so I wonder if there is either a more modern technique or plugin.

我想说自 2004 年以来浏览器供应商很少关注它。

但如果您想要更现代的东西,可以使用 Saxon-JS,它是 XSLT 3.0 的纯 Javascript 实现。它不仅支持 3.0 标准,还具有使其具有交互性的扩展,因此您可以直接在 XSLT 代码中处理用户输入事件。详情见 http://www.saxonica.com/saxon-js/index.xml

免责声明:Saxon-JS 由我公司 Saxonica 生产。