0

This question is very much relevant to this XSLT converts <image> node to <img> tag when outputiing to DOM

Consider this piece of code:

<script type="application/xml" id="data">
    <xsl:copy-of select="/*" />
</script>

This will output the contents of an XML document into of the html page. It is then very easy to parse the data from XML via javascript's DOMParser() object making it easily accessible on the webpage without any need to use XSLT to generate a webpage.

Moving <xsl:copy-of select"/*" /> between the script tags was required to prevent XSLT transformer from transforming node in XML file into tags in HTML.

This worked perfectly, until I've found out the same happens to node as well. Simply put: if XML has node, the output will be broken and unparserable like this:

enter image description here

How to prevent this behaviour? How to stop browser engine from making tag a self-closing one?

new DOMParser().parseFromString()

/\ Will not work with self-closing nodes. (CLARIFICATION: Apparently DOMParser WILL work with self-closing nodes, it's just in this case it wasn't self-closing ie - had no forward slash)


Ok so here are the files that needed to reproduce this:

test.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" indent="no" version="5.0" />

    <xsl:template match="/">
        <xsl:text disable-output-escaping='yes'>&lt;!DOCTYPE html></xsl:text>
        <xsl:apply-templates select="root" />
    </xsl:template>

    <xsl:template match="root">
        <html>
            <head>
                <script type='application/xml'>
                    <xsl:copy-of select="/*" />
                </script>
            </head>
            <body>
                <div>qwe</div>
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

test.xml

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

<root>
    <object>
        <text>text</text>
        <param name="name"></param>
    </object>
</root>

Open test.xml with Edge in Internet Explorer 11 compatibility mode. The "head" should countain a script with distorted xml.

enter image description here

On windows 10 you can open the Developer Tools by doing "Run (Win+R)" -> "%systemroot%\system32\f12\IEChooser.exe" after opening the xml file

6
  • What is the environment for running the XSLT/XPath that does the <xsl:copy-of select="/*" />? Ideally the script element content should be serialized XML. Difficult in XSLT 1 but there are XSLT 1.0 libaries to serialize and/or with MSXML in IE it might be possible to call into J(ava)Script to serialize a node. Commented Apr 11 at 13:58
  • A possible pure XSLT 1 serialization of XML is lenzconsulting.com/xml-to-string. Commented Apr 11 at 13:59
  • I just open the XML file with Edge in IE11 compatibility mode. *.xslt file with all the templates is in the same folder Commented Apr 11 at 14:11
  • But you do use both XSLT transformation based on xml-stylesheet pi in some XML as well as later Javascript run XSLT transformation? The whole processing sequence is not clear to me, as which point you use the script element with xsl:copy-of inside and where you later need to process the contents of the script element. But with XSLT 1, if you need to serialize an XML node, use a library that can do that. Commented Apr 11 at 14:15
  • Nothing really. I've updated the question to include the contents of 2 files - test.xml and test.xslt. I just open test.xml with Edge in IE11 mode and that's it. I do have MSXML4 installed on my computer if this changes anything (I installed it because <xsl:include> directive didn't work without it). I suppose I'll have to use the libs after all. Commented Apr 11 at 14:59

1 Answer 1

1

As for my suggestion, to serialize using the library, here is how that would look (in your real use don't import over HTTP(S), use a local copy you xsl:import):

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

  <xsl:import href="https://lenzconsulting.com/xml-to-string/xml-to-string.xsl"/>

  <xsl:output method="html" indent="no" version="5.0" doctype-system="about:legacy-doctype" />

  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>
  
  <xsl:template match="root">
      <html>
          <head>
              <script type='application/xml'>
                  <xsl:apply-templates select="." mode="xml-to-string"/>
              </script>
          </head>
          <body>
              <div>qwe</div>
          </body>
      </html>
  </xsl:template>

</xsl:stylesheet>

That should give you a script element which as its text/CDATA content has the serialization of the input document's root element.

As for the way to serialize empty elements, in XML it shouldn't matter, but the library allows you to set <xsl:param name="use-empty-syntax" select="false()"/> to get e.g. <param name="name"></param>.

3
  • You saved my hide yet again. This lib totally works and does what's needed. Only quirk that I found is that is closes <param> tag if it's empty, making it self closing tag. But that's ok since DOMParser DOES work with self-closing nodes after all. So result is: xml <object> <param name="name" /> </object> It does not do that for other empty nodes for some reason Commented Apr 12 at 8:14
  • Only thing I'm afraid about is losing this library if the site goes down :) (I did download it for local use but still - what if someone else faces the same problem but the solution is unavailable) Commented Apr 12 at 8:15
  • 1
    @GlennCarver, the library does allow you to set a parameter use-empty-syntax to false() to have empty elements serialized with start and end tag. As for the site going down, well, let's hope Evan keeps it up. Of course we live in the world of XSLT 3 since 2017 where there is a built-in XPath 3.1 function fn:serialize, supported on a wide range of platforms and in a wide range of environments by implementations like Saxon Java, SaxonC, SaxonJS, Saxon.NET and the various Altova XML tools (XML Spy, Raptor), so there are modern, compact alternatives. Not sure there is a way for IE, though. Commented Apr 12 at 8:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.