Use XSLT to pretty print XML/XHTML without corrupting namespace info
I'm trying to use XSLTs (in Javascript) to pretty-print an XHTML doc that has been machine generated. However, the various XSLTs I've tried to use, all mangle the xmlns attributes (see below).
Here is a sample of desired output (made by hand from unindented, compact, XHTML).
<?xml version="1.0" encoding="UTF-8"?>
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns:orx="http://openrosa.org/jr/xforms" xmlns="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa">
<h:head>
<h:title>New Form1</h:title>
....
Here is what I'm getting instead:
<h:html h="http://www.w3.org/1999/xhtml" orx="http://openrosa.org/jr/xforms" xmlns="http://www.w3.org/2002/xforms" xsd="http://www.w3.org/2001/XMLSchema" jr="http://openrosa.org/javarosa">
<h:head>
<h:title>New Fo开发者_StackOverflow中文版rm1</h:title>
...
Notice the xmlns attributes are altered in the 'h:html' tag in the second code snippet. Also the beginning <?xml ...>
tag is missing.
This is (one of many) XSLTs I've used with similar results:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Any ideas on what I'm doing wrong? Am I trying to do the impossible?
If you're wondering why I'm trying to do this: I have to use GWT as the framework for designing a FormDesigner web app. This is the output, but needs to be human readable for the more technically inclined users that want to do by-hand edits. GWT just doesn't do xml pretty printing (as far as I can tell in my searching so far). Thus, we go native to JS land and try for a solution there.
Ideas/solutions would be greatly appreciated!
Edit:
Here is the Javascript that makes use of the XSLT. I call the beautifyXML() function to actual perform the indentation:
//var xsl_string = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template></xsl:stylesheet>';
// from: http://www.xml.com/pub/a/2006/11/29/xslt-xml-pretty-printer.html?page=3
var xsl_string = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\
<xsl:output method="xml" indent="yes"/>\
<xsl:strip-space elements="*"/>\
<xsl:template match="/">\
<xsl:copy-of select="."/>\
</xsl:template>\
</xsl:stylesheet>';
var xsl = (new DOMParser()).parseFromString(xsl_string, "text/xml");
function stringToXml(xml_string) {
return (new DOMParser()).parseFromString(xml_string, "text/xml");
}
function xmlToString(xml) {
return (new XMLSerializer()).serializeToString(xml);
}
function isParseError(xml) {
try {
// console.log( xml.documentElement.firstChild.firstChild.tagName);
return xml.documentElement.tagName == "parsererror" ||
xml.documentElement.firstChild.firstChild.tagName == "parsererror";
}
catch (ex) {
return false;
}
}
function beautifyXml(input) {
var xml = stringToXml(input);
if (isParseError(xml)) {
return input;
}
var transformedXml = xslTransformation(xml, xsl);
return xmlToString(transformedXml);
}
/**
* @param xml
* @param xsl
*/
function xslTransformation(xml, xsl) {
// code for IE
if (window.ActiveXObject) {
var ex = xml.transformNode(xsl);
return ex;
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation && document.implementation.createDocument) {
var xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
var resultDocument = xsltProcessor.transformToFragment(xml, document);
return resultDocument;
}
}
I finally found the answer (only got around to posting it here now).
The issue, as it turns out, wasn't with the XSLT itself but how it was being called by javascript. The line:
var resultDocument = xsltProcessor.transformToFragment(xml, document);
in the last code sample I pasted in my question (near the bottom in the sample), should read:
var resultDocument = xsltProcessor.transformToDocument(xml, document);
(note: transformToFragment becomes transformTo Document) This change causes the existing xmlns attributes to not be ignored and the transformation to occur correctly.
Thanks for all the help! The questions in the comments led me to the right solution.
精彩评论