【问题标题】:XSLT document function doesn't work in chromeXSLT 文档功能在 chrome 中不起作用
【发布时间】:2023-03-18 11:27:01
【问题描述】:

我正在尝试使用 Javascript 转换 XSLT,并尝试让它在 Chrome 和 IE 上运行。入口页面是a.html。它在 IE 中运行良好(本机/兼容模式),但在 Chrome 中无法正常运行,即下拉菜单不是使用选项创建的。

但是,在 chrome 中,如果我打开 data.xml,其中有:

<?xml-stylesheet type="text/xsl" href="render.xslt" ?>

直接在 chrome 中,它被转换得非常好。但是,如果我尝试使用 XSLTProcessor 来做同样的事情,它就行不通了。具体来说,document 函数不起作用。你能帮忙吗?

我的代码如下。

Javascript:

var MSXML2_DOMDocument_6 = "MSXML2.DOMDocument.6.0";
function tranform(xml, xsl) {
    if (window.ActiveXObject || "ActiveXObject" in window) {
        var xmlSerializer = new XMLSerializer();
        var xmlString = xmlSerializer.serializeToString(xml);
        var xslString = xmlSerializer.serializeToString(xsl);

        var xsl = new ActiveXObject(MSXML2_DOMDocument_6);
        xsl.setProperty("AllowXsltScript", true);
        xsl.setProperty("AllowDocumentFunction", true);
        xsl.resolveExternals = true;
        xsl.async = false;
        xsl.loadXML(xslString);

        var xml = new ActiveXObject(MSXML2_DOMDocument_6);
        xml.resolveExternals = true;
        xml.preserveWhiteSpace = true;
        xml.async = false;
        xml.loadXML(xmlString);
        xml.resolveExternals = true;

        ex = xml.transformNode(xsl);
        document.getElementById("example").innerHTML = ex;
    } else if (document.implementation && document.implementation.createDocument) {
        xsltProcessor = new XSLTProcessor();
        xsltProcessor.importStylesheet(xsl);
        resultDocument = xsltProcessor.transformToFragment(xml, document);
        document.getElementById("example").appendChild(resultDocument);
    }
}

function loadXMLDoc() {

    $.ajax({
        method: "GET",
        url: "data.xml",
        dataType: "xml"
    }).then(function (xml) {
            console.log("done xml")
            $.ajax({
                method: "GET",
                url: "render.xslt",
                dataType: "xml"
            }).then(function (xsl) {
                console.log("done xsl")
                tranform(xml, xsl)
            })
        },
        function (e) {
            console.log("Got error in xml", e.status)
        })
}

$(loadXMLDoc)

foo/b.xml:

<dropdowns>
  <dropdown name="xyz">
    <option value="I">Info</option>
    <option value="C">Category</option>
  </dropdown>
</dropdowns>

data.xml:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="render.xslt" ?>
<catalog name="xyz" />

a.html:

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="jquery-3.3.1.js"></script>
    <title>Document</title>
</head>

<body>
    <div id="example"></div>
    <script src="b.js"></script>
</body>

</html>

render.xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="util.xslt" />
    <xsl:output method="html"></xsl:output>
    <xsl:template match="/">
        <h1>
            <xsl:value-of select="/catalog/@name"></xsl:value-of>
        </h1>
        <xsl:call-template name="dropdown">
            <xsl:with-param name="listname">xyz</xsl:with-param>
            <xsl:with-param name="value" select="/catalog/@name"/>
        </xsl:call-template>
    </xsl:template>
</xsl:stylesheet>

util.xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"></xsl:output>
    <xsl:template name="dropdown">
        <xsl:param name="listname"/>
        <xsl:param name="value"/>
        <select>
            <xsl:for-each select="document('foo/b.xml')/dropdowns/dropdown[@name=$listname]/option">
                <option>
                    <xsl:attribute name="value">
                        <xsl:value-of select="@value"/>
                    </xsl:attribute>
                    <xsl:value-of select="."/>
                </option>
            </xsl:for-each>
        </select>
    </xsl:template>
</xsl:stylesheet>

很抱歉,作为 MVE 示例有点长,但它已经完成了。

如果需要任何澄清,请告诉我。

【问题讨论】:

  • 您可以尝试给document() 一个绝对URI 参数(或者使用xml:base 来设置上下文URI)吗?如果它与&lt;?xml-stylesheet?&gt; 一起工作,那么 URI 的组合可能会出错。控制台是否给出错误消息?
  • 我用绝对网址试过了,还是不行。控制台为render.xsltutil.xslt 提供Resource interpreted as Stylesheet but transferred with MIME type application/xslt+xml:。这会是问题的原因吗?
  • 我不知道。根据stackoverflow.com/questions/6715767/…,预期的内容类型应该是text/xsl,因此您可以尝试告诉您的网络服务器使用它来传递.xsl 文件(尽管我怀疑它会有所帮助)
  • @imhotap - 是否可以在任何地方将其设置为text/xsl
  • Chrome 的安全策略似乎不允许导入或文档引用。

标签: xml google-chrome xslt


【解决方案1】:

一般来说,整个方法都是关于嵌套模板。
这已经在这里回答了:How to traverse a nested XML structure using templates

下面还是关于题主的一些问题和说明。

调整了本地服务器,它将文件util.xslt 传递为 Content-Type text/css,就像 chrome 所期望的那样,而不是 application/xslt+xml,脚本仍然无法像预期的那样工作。因此肯定还有另一个与chrome相关的问题。

有趣的一点是,有两个 xslt 文档,其中一个通过application/xslt+xml 被 chrome 传输和接受,但另一个仅作为 text/xmltext/xsl (是的,两者都被 chrome 接受,我试过了)。

因此,interesting post about versions of xml / xslt 可能对这个问题没有用处。

以下是详细的控制台消息:

服务器的调整已通过以下几行完成,如果请求的文件名具有后缀 xslt 并且预期的 mime-type 为 text/css,则更改 Content-Type(mime-type):

<If "%{REQUEST_FILENAME} =~ m#\.xslt$# && %{HTTP:Accept} =~ m#^text\/css#">
    Header set "Content-Type" "text/css"
</If>

火狐

值得注意的是,firefox 将util.xslt 完全隐藏在网络面板中:

此外,Firefox 接受 ActiveXObject 和 XSLTProcessor 这两种方法。根据 JavaScript 中的逻辑,默认设置为 ActiveXObject,该版本在下拉动画方面看起来也更流畅。

当 xml-version 设置为 1.1 时,Firefox 会抱怨,因此使用 版本号可能无法真正帮助提高浏览器兼容性。

【讨论】:

    【解决方案2】:

    这是一个已知问题,自 2009 年以来一直存在。Chrome 团队甚至没有任何修复它的计划,他们正计划从 chrome 中删除它的支持(不确定何时)。但是有一个解决这个问题的方法。将您的 xml 数据转换为 xslt,然后您可以将其导入样式表。

    所以你的 JavaScript 代码将保持不变。

    foo/b.xml 会变成 foo/b.xslt

     <?xml version="1.0" encoding="UTF-8"?>
     <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:template name="dropdowns">
        <xsl:param name="listname"/>
        <xsl:param name="value"/>
        <xsl:choose>
            <xsl:when test="$listname='xyz'">
                <xsl:call-template name="option">
                    <xsl:with-param name="value">I</xsl:with-param>
                    <xsl:with-param name="label">Info</xsl:with-param>
                    <xsl:with-param name="selectedValue" select="$value"/>
                </xsl:call-template>
                <xsl:call-template name="option">
                    <xsl:with-param name="value">C</xsl:with-param>
                    <xsl:with-param name="label">Category</xsl:with-param>
                    <xsl:with-param name="selectedValue" select="$value"/>
                </xsl:call-template>
            </xsl:when>
    
        </xsl:choose>
     </xsl:template>
    
     <xsl:template name="option">
        <xsl:param name="label"/>
        <xsl:param name="value"/>
        <xsl:param name="selectedValue"/>
        <option value="{$value}">
            <xsl:if test="$value = $selectedValue">
                <xsl:attribute name="selected">selected</xsl:attribute>
            </xsl:if>
            <xsl:value-of select="$label"/>
        </option>
    </xsl:template>
    </xsl:stylesheet>
    

    util.xslt:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="foo/b.xslt" />
    <xsl:output method="html" />
    
    <xsl:template name="dropdown">
        <xsl:param name="listname"/>
        <xsl:param name="value"/>
        <select>
            <xsl:call-template name="dropdowns">
                <xsl:with-param name="listname" select="$listname"/>
                <xsl:with-param name="value" select="$value"/>
            </xsl:call-template>
        </select>
    </xsl:template>
    </xsl:stylesheet>
    

    render.xslt:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:import href="util.xslt" />
    <xsl:output method="html"></xsl:output>
    <xsl:template match="/">
        <h1>
            <xsl:value-of select="/catalog/@name"></xsl:value-of>
        </h1>
        <xsl:call-template name="dropdown">
            <xsl:with-param name="listname">xyz</xsl:with-param>
            <xsl:with-param name="value">C</xsl:with-param>
        </xsl:call-template>
    </xsl:template>
    </xsl:stylesheet>
    

    通过这些更改,您可以在页面中创建适用于 IE 和 chrome 的下拉菜单。

    【讨论】:

    • 没有 AFAIK,Chrome 不支持。无法导入 xml 文件,因为 Document 功能无法正常工作。
    【解决方案3】:

    我找到了解决此问题的解决方法[1]

    在 chrome 中,&lt;xsl:import&gt; 在 Javascript 中转换时可以正常工作。因此,我将我的 XML 转换为 XSL &lt;xsl:choose&gt;,每个 dropdown 标记使用 &lt;xsl:when&gt;

    更新util.xslt

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:output method="html"></xsl:output>
        <xsl:template name="dropdown">
            <xsl:param name="listname"/>
            <xsl:param name="value"/>
            <select>
                <xsl:choose>
                    <xsl:when name="$listname='xyz'">
                        <option value="I">Info</option>
                        <option value="C">Category</option>
                    </xsl:when>
                </xsl:choose>
            </select>
        </xsl:template>
    </xsl:stylesheet>
    

    1.我同意这不是一个很好的解决方法,当然也不是一个通用的解决方法。如果有人有更好的解决方案,请将其作为答案发布。

    【讨论】:

      猜你喜欢
      • 2011-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-27
      • 2017-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多