As you asked for alternatives, the post you linked to discussing the use of the identity transformation proposed by Dimitre Novatchev also has a comment suggesting the use of the XPath visualizer stylesheet instead of the identity transformation. So to demonstrate that that is possible I made some adaptions to the XSLT and CSS and Javascript to allow it to be used inside another HTML document instead of creating a separate, complete HTML document, the result is https://martin-honnen.github.io/js/2017/pretty-print/pretty-print-test1.html which does work for me in on Windows 10 with current versions of Edge, Chrome and Firefox. I don't have Safari to test. It will certainly not work as written with IE as I have solely used the XSLTProcessor API in Javascript first introduced in Mozilla and and now be supported in anything but IE; if you need IE support then you should be able to have that by using IE specific code to run the XSLT transformation.
Here is the code of the HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Testing a proof of concept of pretty-printing of an XML DOM tree as a HTML collapsible table structure</title>
<link rel="stylesheet" type="text/css" href="pretty-print1.css"/>
<script>
var prettyPrinter = new XSLTProcessor();
(function() {
var req = new XMLHttpRequest();
req.open('GET', 'pretty-print1.xsl');
req.onload = function() {
prettyPrinter.importStylesheet(req.responseXML);
};
req.send();
}())
function prettyPrint(doc) {
return prettyPrinter.transformToFragment(doc, document);
}
function prettyPrintCollapseExpandHandler(event) {
try {
var thisNode = event.target;
var par = event.target.parentNode;
if (thisNode.nodeName == 'TD' && thisNode.className == 'expander') {
if (par.parentNode.className == 'expander-closed') {
par.parentNode.className = '';
thisNode.textContent = '-';
}
else {
par.parentNode.className = 'expander-closed';
thisNode.textContent = '+';
}
}
} catch (e) {
}
}
</script>
<script>
document.addEventListener('DOMContentLoaded',
function() {
var req = new XMLHttpRequest();
req.open('GET', 'input1.xml');
req.onload = function() {
document.getElementById('result').appendChild(prettyPrint(req.responseXML));
};
req.send();
},
false
);
</script>
</head>
<body>
<section>
<h1>Testing a proof of concept of pretty-printing of an XML DOM tree as a HTML collapsible table structure</h1>
<section id="result">
<h2>Example result</h2>
</section>
</section>
</body>
</html>
the XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- The following is not used because of a bug in Mozilla :( -->
<!--
<xsl:key name="kattPref" match="@*"
use="concat(generate-id(..), '|', substring-before(., ':'))"/>
-->
<xsl:output method="html"/>
<xsl:template match="/">
<div class="pretty-print" onclick="prettyPrintCollapseExpandHandler(event);">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="*">
<div class="indent">
<span class="markup"><</span>
<xsl:variable name="class" select="'elemname'"/>
<span class="{$class}">
<xsl:value-of select="name(.)"/>
</span>
<xsl:call-template name="findNamespace"/>
<xsl:apply-templates select="@*"/>
<span class="markup">/></span>
</div>
</xsl:template>
<xsl:template match="*[text()]">
<xsl:variable name="class" select="'elemname'"/>
<div class="indent">
<span class="markup"><</span>
<span class="{$class}">
<xsl:value-of select="name(.)"/>
</span>
<xsl:call-template name="findNamespace"/>
<xsl:apply-templates select="@*"/>
<span class="markup">></span>
<!--<span class="text">
<xsl:value-of select="."/> -->
<xsl:apply-templates/>
<!--</span>-->
<span class="markup"></</span>
<span class="elemname">
<xsl:value-of select="name(.)"/>
</span>
<span class="markup">></span>
</div>
</xsl:template>
<xsl:template match="*[* or processing-instruction() or comment()
or string-length(text()) > 50]" priority="10">
<xsl:variable name="class" select="'elemname'"/>
<table>
<tr>
<td class="expander">
-
<div/>
</td>
<td>
<span class="markup"><</span>
<span class="{$class}">
<xsl:value-of select="name(.)"/>
</span>
<xsl:call-template name="findNamespace"/>
<xsl:apply-templates select="@*"/>
<span class="markup">></span>
<div class="expander-content">
<xsl:apply-templates/>
</div>
<span class="markup"></</span>
<span class="elemname">
<xsl:value-of select="name(.)"/>
</span>
<span class="markup">></span>
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="@*">
<xsl:variable name="vPos" select="position()"/>
<xsl:variable name="vPref" select="substring-before(name(), ':')"/>
<xsl:if test="$vPref
and
not(../@*[position() < $vPos]
[substring-before(name(), ':')
= $vPref]
)">
<xsl:call-template name="findNamespace"/>
</xsl:if>
<!-- The following is not used because of a bug in Mozilla :( -->
<!--
<xsl:if test=
"generate-id()
=
generate-id(key('kattPref',
concat(generate-id(..), '|', substring-before(., ':'))
)[1]
)">
<xsl:call-template name="findNamespace"/>
</xsl:if>
-->
<xsl:variable name="class" select="'attrname'"/>
<xsl:variable name="class2" select="'markup'"/>
<xsl:variable name="class3" select="'attrvalue'"/>
<xsl:text> </xsl:text>
<span class="{$class}">
<xsl:value-of select="name(.)"/>
</span>
<span class="{$class2}">="</span>
<span class="{$class3}">
<!-- <xsl:value-of select="."/> -->
<xsl:call-template name="replaceAmpersands">
<xsl:with-param name="vString" select="string(.)"/>
</xsl:call-template>
</span>
<span class="{$class2}">"</span>
</xsl:template>
<xsl:template match="text()">
<xsl:variable name="class" select="'text'"/>
<span class="{$class}">
<!-- <xsl:value-of select="."/> -->
<xsl:call-template name="replaceAmpersands">
<xsl:with-param name="vString" select="string(.)"/>
</xsl:call-template>
</span>
</xsl:template>
<xsl:template match="processing-instruction()">
<xsl:variable name="class" select="'indent pi'"/>
<div class="{$class}">
<?
<xsl:value-of select="name(.)"/>
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
?>
</div>
</xsl:template>
<xsl:template match="processing-instruction()[string-length(.) > 50]">
<xsl:variable name="class" select="'pi'"/>
<xsl:variable name="class2" select="'indent expander-content'"/>
<table>
<tr>
<td class="expander">
-
<div/>
</td>
<td class="{$class}">
<?
<xsl:value-of select="name(.)"/>
<div class="{$class2}">
<xsl:value-of select="."/>
</div>
<xsl:text>?></xsl:text>
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="comment()">
<xsl:variable name="class" select="'comment indent'"/>
<div class="{$class}">
<!--
<xsl:value-of select="."/>
-->
</div>
</xsl:template>
<xsl:template match="comment()[string-length(.) > 50]">
<xsl:variable name="class" select="'comment'"/>
<xsl:variable name="class2" select="'indent expander-content'"/>
<table>
<tr>
<td class="expander">
-
<div/>
</td>
<td class="{$class}">
<!--
<div class="{$class2}">
<xsl:value-of select="."/>
</div>
-->
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="findNamespace">
<xsl:variable name="vName" select="substring-before(name(), ':')"/>
<xsl:variable name="vUri" select="namespace-uri(.)"/>
<xsl:variable name="vAncestNamespace">
<xsl:call-template name="findAncNamespace">
<xsl:with-param name="pName" select="$vName"/>
<xsl:with-param name="pUri" select="$vUri"/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="not(number($vAncestNamespace))">
<xsl:if test="namespace-uri()
or
not(generate-id()
=
generate-id(../@*[name()
=
name(current())]
)
)">
<xsl:if test="parent::* or namespace-uri() or contains(name(), ':')">
<xsl:text> </xsl:text>
<span class="namespace">
<xsl:value-of select="'xmlns'"/>
<xsl:if test="contains(name(), ':')">
<xsl:value-of select="concat(':', $vName)"/>
</xsl:if>
</span>
<span class="markup">="</span>
<span class="namespace">
<xsl:value-of select="namespace-uri()"/>
</span>
<span class="markup">"</span>
</xsl:if>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="findAncNamespace">
<xsl:param name="pNode" select="."/>
<xsl:param name="pName" select="substring-before(name(), ':')"/>
<xsl:param name="pUri" select="namespace-uri(.)"/>
<xsl:choose>
<xsl:when test="not($pNode/parent::*)
and not($pName) and not($pUri)">1</xsl:when>
<xsl:when test="not($pNode/parent::*)">0</xsl:when>
<xsl:otherwise>
<xsl:variable name="vSamePrefs"
select="number($pName
= substring-before(name($pNode/..), ':')
)"/>
<xsl:variable name="vSameUris"
select="number($pUri = namespace-uri($pNode/..))"/>
<xsl:choose>
<xsl:when test="$vSamePrefs and not($vSameUris)">0</xsl:when>
<xsl:when test="not($vSamePrefs)">
<xsl:call-template name="findAncNamespace">
<xsl:with-param name="pNode" select="$pNode/.."/>
<xsl:with-param name="pName" select="$pName"/>
<xsl:with-param name="pUri" select="$pUri"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="replaceAmpersands">
<xsl:param name="vString"/>
<xsl:variable name="vAmp">&</xsl:variable>
<xsl:choose>
<xsl:when test="contains($vString, $vAmp)">
<xsl:value-of select="substring-before($vString, $vAmp)"/>
<xsl:value-of select="concat($vAmp, 'amp;')"/>
<xsl:call-template name="replaceAmpersands">
<xsl:with-param name="vString"
select="substring-after($vString, $vAmp)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$vString"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Take the CSS from https://martin-honnen.github.io/js/2017/pretty-print/pretty-print1.css, it is all meant anyway as a proof of concept, not as polished, finished code.
These days I would rather suggest to a worked out solution like https://github.com/pgfearo/xmlspectrum that might work in the browser with the help of Saxon-CE or Saxon-JS.