不推荐使用DOCTYPE,Xinclude不会这样做

时间:2017-06-01 18:27:05

标签: xml xslt doctype xinclude

我需要一种方法来包含一个不包含全局开始/结束标记/元素的碎片XML。片段正在增长,因为程序不时会将数据(更多块)附加到其中,因此它既不会有结束标记也不会有起始标记。我使用了!DOCTYPE和!ENTITY但是这个被弃用了,新的Xinclude似乎没有办法导入它,因为它强制片段有一个"一个"打开和关闭标签。

更多信息:以下适用于IE-10,但在IE-11中不起作用。后者不会导入文件 current.log

注意:根据此网站,Microsoft Edge不支持它:https://docs.microsoft.com/en-us/internet-explorer/ie11-deploy-guide/deprecated-document-modes

<?xml version='1.0' encoding='ISO-8859-1'?>
<?xml-stylesheet type='text/xsl' href='IndexLog.xsl'?>

<!DOCTYPE myRoot [<!ENTITY thisMonthLog SYSTEM "current.log">]>

<myRoot>
    &thisMonthLog;
</myRoot>

日志 current.log 如下所示:

<block>
   <a>any text</a>
   <b>any text</b>
   <c>any text</c>
   <d>any text</d>
   <e>any text</e>
</block>
<block>
   <a>any text</a>
   <b>any text</b>
   <c>any text</c>
   <d>any text</d>
   <e>any text</e>
</block>

1 个答案:

答案 0 :(得分:0)

根据您的评论,我了解您直接使用IE 11从文件系统加载XML文档。我认为IE已默认为XSLT使用MSXML 6而不是MSXML 3,默认情况下MSXML 6禁止DTD而不是加载外部实体。我知道绕过它的唯一方法是使用带脚本的MSXML 6并设置它允许DTD的属性,加载外部资源(对于你的情况,因为DTD仅用于加载外部实体,禁用验证) ):

<?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" indent="yes" version="5" doctype-system="about:legacy-doctype"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>Test</title>
                <script>
                    function runXslt(xmlUri, xsltUri, targetElement) {
                      var xmlDoc = new ActiveXObject('Msxml2.DOMDocument.6.0');
                      xmlDoc.async = false;
                      xmlDoc.resolveExternals = true;
                      xmlDoc.validateOnParse = false;
                      xmlDoc.setProperty('ProhibitDTD', false);
                      xmlDoc.load(xmlUri);

                      var xsltDoc = new ActiveXObject('Msxml2.DOMDocument.6.0');
                      xsltDoc.async = false;
                      xsltDoc.load(xsltUri);

                      targetElement.insertAdjacentHTML('beforeEnd', xmlDoc.documentElement.transformNode(xsltDoc));
                    }
                </script>
                <script>
                    document.addEventListener(
                      'DOMContentLoaded',
                      function() {
                        runXslt('test201706070101.xml', 'test2017060701.xsl', document.body);
                      },
                      false
                    );
                </script>
            </head>
            <body>
                <h1>Test</h1>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="myRoot">
        <section>
            <h2>Content</h2>
            <xsl:apply-templates/>
        </section>  
    </xsl:template>

    <xsl:template match="block">
        <ul>
            <xsl:apply-templates/>
        </ul>
    </xsl:template>

    <xsl:template match="block/*">
        <li>
            <xsl:apply-templates/>
        </li>
    </xsl:template>

</xsl:stylesheet>

这样,如果输入文档test201706070101.xml的内容为

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test2017060701.xsl"?>
<!DOCTYPE myRoot [
  <!ENTITY thisMonthLog SYSTEM "test201706070102.xml">
]>
<myRoot>
    &thisMonthLog;
</myRoot>
在IE 11中加载

并启用脚本,解析完整日志,例如,第二个文件

<?xml version="1.0" encoding="UTF-8"?>
<block>
    <a>any text</a>
    <b>any text</b>
    <c>any text</c>
    <d>any text</d>
    <e>any text</e>
</block>
<block>
    <a>any text</a>
    <b>any text</b>
    <c>any text</c>
    <d>any text</d>
    <e>any text</e>
</block>

并且样式表已经发布,IE窗口中的输出是

Test


Content
•any text
•any text
•any text
•any text
•any text
•any text
•any text
•any text
•any text
•any text

所以外部实体已被加载。主要缺点显然是需要脚本,另一个缺点是使用MSXML和ActiveXObject的脚本与Edge不兼容,因为它不支持ActiveXObject。

我发布这个答案作为建议,如果你想依赖IE进行XSLT转换可能会有什么帮助,从长远来看,最好将XSLT转换为HTML转换到像.NET这样的平台,你可以更好地控制XML解析和XSLT处理如何交互。

示例文件在https://martin-honnen.github.io/xslt/2017/test201706070101.xmlhttps://martin-honnen.github.io/xslt/2017/test201706070102.xmlhttps://martin-honnen.github.io/xslt/2017/test2017060701.xsl处于联机状态,但我知道您希望在本地而不是通过HTTP(S)执行此操作。