Why does XSLT add newline (carriage return) in IE1

2019-08-14 04:24发布

问题:

This just started with IE10 as far as I can tell.

It's not an issue in FF.

Using XMLHttpRequest to get some xml data, then display it using xslt...

The xslt transformation is automatically adding new lines in seemingly random locations where there is a space in an elements data.

If I preview the data using getElementsByTagName, the data is intact, no spaces have been converted to a newlines.

Since html treats new lines as a space, you can not see the issue if you simply display the text or place it in an input box, BUT, if the data is stored in a hidden element and you show it using the alert function you can see that there is a newline/carriage return in the output data.

The issue seems to be worse if there are NOT carriage returns after the elements in the original xml data. I've actually been able to get around this issue in some cases by adding a carriage return after each element. Some cases, not all.

It's almost as if when the transformer is trying to read the data it splits the data at spaces for readability and it automatically adds a carriage return.

Example:

xsltTest.htm

<!DOCTYPE html>
<html>
<head>
    <title>xslt test</title>
    <script type="text/javascript" language="javascript">

        function loadFile(f) {
            xhttp = new window.XMLHttpRequest
            xhttp.open("GET", f, false)
            xhttp.setRequestHeader("Cache-Control", "no-cache");
            xhttp.setRequestHeader("pragma", "no-cache");
            xhttp.send("")

            //in IE10 this seems to show where the new lines get added
            alert(xhttp.responseText)

            var xml = xhttp.responseXML

            displayData(xml, 'xsltTest.xslt', 'DataDiv')

        }

        function displayData(xmlResp, xslFile, targetObj) {

            var xml = new ActiveXObject("MSXML2.DomDocument");
            xml.async = false;
            xml.load(xmlResp);

            var xsl = new ActiveXObject("MSXML2.FreeThreadedDomDocument");
            xsl.async = false;
            xsl.load(xslFile);

            xsl_template = new ActiveXObject("Msxml2.XSLTemplate")
            xsl_template.stylesheet = xsl;

            xslProc = xsl_template.createProcessor()
            xslProc.input = xml

            xslProc.transform()
            document.getElementById(targetObj).innerHTML = xslProc.output
        }

        function popData(idx,e) {
            alert(document.getElementById('data_'+idx+'_'+e).value)
        }

    </script>
</head>
<body>
<center>
<input type="button" id="WithCRButton" value="Load File WITH CarriageReturns" onclick="loadFile('DataWithCR.xml')" />
<input type="button" id="WithoutCRButton" value="Load File WITHOUT CarriageReturns" onclick="loadFile('DataWithoutCR.xml')" />
<div style="border:1px solid black;width:100%" id="DataDiv">
</div>
</center>
</body>
</html>

xsltTest.xslt

<?xml version="1.0" encoding="iso-8859-1"?>

<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xs="http://www.w3.org/2001/XMLSchema">


    <xsl:template match="/">
        <table>
            <xsl:for-each select="TestData/field">
                <tr>
                    <td>
                        <xsl:value-of select="elementData1"/>
                    </td>
                    <td>
                        <input type="hidden">
                            <xsl:attribute name="value"><xsl:value-of select="elementData1"/></xsl:attribute>
                            <xsl:attribute name="id">data_<xsl:value-of select="position()"/>_1</xsl:attribute>
                        </input>
                        <input type="button" value="show hidden value">
                            <xsl:attribute name="onclick">popData('<xsl:value-of select="position()"/>','1')</xsl:attribute>
                        </input>
                    </td>
                    <td>
                        <xsl:value-of select="elementData2"/>
                    </td>
                    <td>
                        <input type="hidden">
                            <xsl:attribute name="value"><xsl:value-of select="elementData2"/></xsl:attribute>
                            <xsl:attribute name="id">data_<xsl:value-of select="position()"/>_2</xsl:attribute>
                        </input>
                        <input type="button" value="show hidden value">
                            <xsl:attribute name="onclick">popData('<xsl:value-of select="position()"/>','2')</xsl:attribute>
                        </input>
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>

</xsl:stylesheet>

DataWithCR.xml

<TestData>
<field>
<elementData1>ThisHasNoSpaces</elementData1>
<elementData2>ThisHasA Space</elementData2>
</field>
<field>
<elementData1>ThisHasNoSpaces</elementData1>
<elementData2>ThisHasA Space</elementData2>
</field>
<field>
<elementData1>ThisHasNoSpaces</elementData1>
<elementData2>ThisHasA Space</elementData2>
</field>
<field>
<elementData1>ThisHasNoSpaces</elementData1>
<elementData2>ThisHasA Space</elementData2>
</field>
</TestData>

DataWithoutCR.xml

<TestData><field><elementData1>ThisHasNoSpaces</elementData1><elementData2>ThisHasA Space</elementData2></field><field><elementData1>ThisHasNoSpaces</elementData1><elementData2>ThisHasA Space</elementData2></field><field><elementData1>ThisHasNoSpaces</elementData1><elementData2>ThisHasA Space</elementData2></field><field><elementData1>ThisHasNoSpaces</elementData1><elementData2>ThisHasA Space</elementData2></field></TestData>

回答1:

I found that if I use "ActiveXObject("Msxml2.XMLHTTP")" instead of "window.XMLHttpRequest" the issue goes away.

It seems that Microsoft just implemented the browser-native "window.XMLHttpRequest" ... but it has bugs AND limitations.

For example, "ActiveXObject("Msxml2.XMLHTTP")" has the transformNode method, but "window.XMLHttpRequest" does not.

For browser compatibility in my javascript code I was creating the object as follows:

var XMLDoc = (window.XMLHttpRequest) ? (new XMLHttpRequest()) : (new ActiveXObject("Microsoft.XMLHTTP"))

...so in IE, as long as window.XMLHttpRequest did not exist it was using the ActiveXObject. But now that it does exist it's using it, along with all it's bugs and limitations.

I am now in the process of reversing that conditional statement everywhere its called to default to the ActiveXObject if it's available...

var XMLDoc = (window.ActiveXObject) ? (new ActiveXObject("Msxml2.XMLHTTP")) : (new XMLHttpRequest())