【问题标题】:Transform XML with multiple XSL files使用多个 XSL 文件转换 XML
【发布时间】:2017-04-27 21:35:17
【问题描述】:

我有一些 XML 想使用一些 XSL 文件转换成 HTML。这些 XSL 文件都是通过 xsl:import 和 xsl:include 语句关联的,并且都是完成转换所必需的。

我知道 XSL 可以工作,因为在浏览器打开的预先创建的 XML 文件中使用 <?xml-stylesheet type="text/xsl" href="transform.xsl"?> 指令会显示我想要的输出。问题是我希望能够在动态生成的 XML 上复制此功能。

我可以看到有两种方法可以做到这一点,但两者似乎都有我无法解决的限制。

第一个解决方案是使用 Javascript 来转换 XML。据我所知,这将需要 XSLTProcessor 对象来加载多个 XSL 文件,但 Chrome(可能还有其他浏览器)不太支持 xsl:import - http://code.google.com/p/chromium/issues/detail?id=8441

我还研究了将 XML 写入 iFrame 或新窗口,但 <?xml-stylesheet type="text/xsl" href="transform.xsl"?> 指令在结果窗口中被注释掉了。实际上,任何写入新窗口的内容都是 HTML——我还没有找到将 XML 写入新窗口的方法。

那么我怎样才能让浏览器窗口显示用一组 XSL 文件转换的 XML 文件的结果呢?

更新

以下是我对这个问题的研究结果。

可能的解决方法:使用 emscripten 将 xsltproc 之类的工具编译成 JavaScript。我实际上已经这样做了 - 请参阅https://github.com/mcasperson/xsltproc.js

问题:在 Firefox 中速度非常慢(在 Chrome 中需要 5 秒在 Firefox 中需要 30+),并且您无法在 Chrome Web Worker 中运行代码 - https://code.google.com/p/chromium/issues/detail?id=252492

可能的解决方法:根本不使用 XSL,而是使用 CSS 样式表显示 XML。

问题:在浏览器开始实现css attr(atrributename, url) 函数之前,无法将XML 属性中的文件引用视为字符串以外的任何内容,这使得无法显示图像。

可能的解决方法:将所有 XSL 文件合并到一个样式表中

问题:这在某种程度上是可能的(请参阅Merge multiple xslt stylesheets),但是 xsl:import 和 xsl:include 具有特定的语义,当简单地将文件内容替换为xsl:import 或 xsl:include 语句。对于分解为多个文件的大型 XSL 转换,此解决方案需要大量手动工作。

可能的解决方法:将 XML 的内容写入 iframe 或新窗口。

问题:无法将 XML 写入新窗口或 iframe。写入这些元素的内容始终假定为 HTML,并插入到 HTML->BODY 元素中。

可能的解决方法:创建一个接受 XML 的服务器端服务,然后使用 XSL 样式表指令返回该 XML。然后可以将服务 URL 用作 iframe 或新窗口的 src 属性。

问题:服务必须是 GET 端点,这意味着要返回的 XML 必须作为查询参数包含在内,这意味着您最终会遇到问题URL 的长度。

可能的解决方法:使用 javascript XSL 库,例如 Saxonica CE

问题:这可能确实有效(我没有尝试过),但 Saxonica CE 不是开源的(这是我们项目的要求)。

【问题讨论】:

  • blog.echo-flow.com/2010/06/23/… 可能是一个解决方案...
  • 您可以让 XSLTProcessor 导入第一个样式表,使用 transformToDocument() 进行第一次转换,保存结果,加载第二个样式表并执行另一个 transformToDocument(),提供第一次转换的结果。
  • 为什么要在浏览器中转换 XML?只需在服务器端执行即可。
  • Tomalak - 实时预览将 XML 转换为 HTML 的样子。在服务器上执行此操作需要不断调用服务器端服务,这会浪费大量资源。
  • //IE html = xml.transformNode(xsl); //FF, Chrome xsltProcessor = new XSLTProcessor(); xsltProcessor.importStylesheet(xsl); html = xsltProcessor.transformToFragment(xml, document);

标签: javascript xml xslt


【解决方案1】:

如果您想要仅浏览器的解决方案,我会这样做:

静态xml

制作一个仅包含对 xsl 的调用的简单静态 xml。这是在浏览器中打开的 xml - 总是。此 xml 文件可以包含用于控制流程的属性设置,也可以根本不包含此示例。

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="cartoon2html.xsl"?>
<xml/>

动态纯xml

使用定义的名称以您喜欢的方式生成动态 XML - 在我的例子中是 cartoons.xml。

<?xml version="1.0" encoding="utf-8"?>
<cartoons>
    <cartoon name="Donald Duck" publisher="Walt Disney" />
    <cartoon name="Mickey Mouse" publisher="Walt Disney" />
    <cartoon name="Batman" publisher="DC Comics" />
    <cartoon name="Superman" publisher="DC Comics" />
    <cartoon name="Iron Man" publisher="Marvel Comics" />
    <cartoon name="Spider-Man" publisher="Marvel Comics" />
</cartoons>

带有文档加载的 XSLT

使用 xslt 中的文档外借来引用生成的动态 xml。通过在第一个 apply-templates 中使用 select,所有其他模板都将按预期工作。

仔细查看代码顶部和底部的变量引用。这就是施展魔法的地方。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:variable name="cartoons" select="document('cartoons.xml')/cartoons" />

    <xsl:template match="/">
        <html>
            <head>
                <title>Cartoons</title>
                <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
            </head>
            <body>
                <xsl:apply-templates select="$cartoons" />
            </body>
        </html>
    </xsl:template>

    <xsl:template match="cartoons">
        <table>
            <xsl:apply-templates />
        </table>
    </xsl:template>

    <xsl:template match="cartoon">
        <tr>
            <td><xsl:value-of select="@name" /></td>
            <td><xsl:value-of select="@publisher" /></td>
        </tr>
    </xsl:template>

</xsl:stylesheet>

您可以将这三个文件保存到选择的目录中,然后在 firefox 中打开静态 xml 文件。 (Chrome 或许 Safari 必须通过网络服务器提供文件以执行转换)。

【讨论】:

    【解决方案2】:

    我建议使用 jquery 来导入和设置 XML 样式。

    这样的东西可以让您在调用函数(链接到按键或刷新按钮甚至计时器的函数)时导入 XML。

    $.ajax({
        type: "GET",
        url: "FILENAME.xml",
        dataType: "xml",
        success: function(xml) {
            $(xml).find('site').each(function(){ //finds parent node
                var id = $(this).attr('id'); //id of parent node
                var title= $(this).find('title').text();  //finds title node within parent node
                var url = $(this).find('url').text(); //finds URL node within parent node
                var description = $(this).find('descr').text(); //etc...
                var img = $(this).find('img').text(); //etc...
    
                // Creates div with id of parent node (for individual styling)
                $('<div id="link_'+id+'">')
                    .addClass('add a div class')
                //sets css of div
                    .css({set css})
                // Sets the inner HTML of this XML allocated div to hyperlinked 'title' with 'description' and an 'img'
                    .html('<a href="'+url+'">'+title+'</a>'+description+'<img src="'+img+'">')                  
                // Append the newly created element to body
                    .appendTo('#holder');
        }
        }
    })
    

    XML 看起来像这样:

    <site id="0">
     <url>http://blah.com</url>
     <img>imgs/image1.png</img>
     <description>this is a description</description>
     <title>Title</title>
    </site>
    
    <site id="1">
     <url>http://filler.com</url>
     <img>imgs/image2.jpg</img>
     <description>this is another description</description>
     <title>Title 2</title>
    </site>
    

    当然,您可以将 XML 导入表格或任何其他类型的 HTML 元素,而不是导入 div。

    【讨论】:

      【解决方案3】:

      我刚才也遇到了同样的问题。 我的解决方案是将包含直接传播到 XML 中。 此代码已在 Chrome、Firefox 和 IE 10、9、8 和 7 下测试。

      function propegateIncludes(dname,xml, isExplorer) {
          var preTag = isExplorer ? "xsl:" : "";
      
          var TAG_STYLESHEET = preTag + "stylesheet", TAG_INCLUDE = preTag
              + "include", TAG_TEMPLATE = preTag + "template";
      
          var stylesheets = xml.getElementsByTagName(TAG_STYLESHEET);
          if (stylesheets.length == 0) {
              return;
          }
      
          var includes = xml.getElementsByTagName(TAG_INCLUDE);
          if (includes.length == 0) {
              return;
          }
      
          var stylesheet = stylesheets[0];
          var path = dname.substring(0, dname.lastIndexOf('/'));
      
          for ( var i = 0; i < includes.length; i++) {
              var args = includes[i].attributes;
              var includeXml = null;
      
              for ( var a = 0; a < args.length; a++) {
                  if (args[a].nodeName == "href") {
                      includeXml = loadXMLDoc(path + "/" + args[a].nodeValue);
                      break;
                  }
              }
      
              stylesheet.removeChild(includes[i]);
      
              if (includeXml != null) {
                  var templates = includeXml.getElementsByTagName(TAG_TEMPLATE);
      
                  for (var t = 0; t < templates.length; ++t) {
                      stylesheet.appendChild(templates[t].cloneNode(true));
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-16
        • 1970-01-01
        • 1970-01-01
        • 2012-08-12
        • 1970-01-01
        • 1970-01-01
        • 2012-02-01
        相关资源
        最近更新 更多