xmlxsltdoctypexinclude

DOCTYPE is deprecated and Xinclude does not do it


I need a way to include a fragmented XML not containing a global opening/closing tag/element. The fragment is growing because a program is appending data (more blocks) into it from time to time, so it neither going to have an ending tag nor an starting tag. I have used !DOCTYPE with a !ENTITY but this is being deprecated and the new Xinclude does not seem to have a way to import it as it forces the fragment to have "one" opening and closing tag.

More info: The following works fine with IE-10 but it does not work in IE-11. The latter does not import the file current.log.

Note: Microsoft Edge does not support it according to this web site: https://learn.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>

the log current.log looks like this:

<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>

Solution

  • Based on your comments I understand you load an XML document from the file system directly with IE 11. I think IE has moved to use MSXML 6 instead of MSXML 3 by default for XSLT and MSXML 6 by default prohibits DTDs and does not load external entities. The only way I know to circumvent that is to use MSXML 6 with script and to set the properties it has to allow DTDs, load external resources (and for your case, as the DTD is only used to load an external entity, to disable validation):

    <?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>
    

    That way, if the input document test201706070101.xml with the content

    <?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>
    

    is loaded in IE 11 and scripting is enabled, the full log is parsed, e.g. with the second document having

    <?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>
    

    and the stylesheet being as already posted, the output in the IE window is

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

    so the external entity has been loaded. Major drawback is obviously that script is needed, another drawback is that the used script with MSXML and ActiveXObject is not compatible with Edge as that doesn't support ActiveXObject.

    I post that answer as a suggestion on what might help if you want to rely on IE for XSLT transformation, in the long end it might be better to move the XSLT to HTML transformation to a platform like .NET where you better control how XML parsing and XSLT processing interact.

    Example files are online at https://martin-honnen.github.io/xslt/2017/test201706070101.xml, https://martin-honnen.github.io/xslt/2017/test201706070102.xml and https://martin-honnen.github.io/xslt/2017/test2017060701.xsl although I understand you want to do that locally and not over HTTP(S).