Fin utskrift av XML med javascript
Jag har en sträng som representerar ett icke-indenterat XML som jag skulle vilja formatera snyggt. Till exempel:
<root><node/></root>
bör bli:
<root>
<node/>
</root>
Syntaxmarkering är inte ett krav. För att ta itu med problemet omvandlar jag först XML för att lägga till radbrytningar och blanksteg och använder sedan en pre-tagg för att skriva ut XML. För att lägga till nya rader och blanksteg skrev jag följande funktion:
function formatXml(xml) {
var formatted = '';
var reg = /(>)(<)(\/*)/g;
xml = xml.replace(reg, '$1\r\n$2$3');
var pad = 0;
jQuery.each(xml.split('\r\n'), function(index, node) {
var indent = 0;
if (node.match( /.+<\/\w[^>]*>$/ )) {
indent = 0;
} else if (node.match( /^<\/\w/ )) {
if (pad != 0) {
pad -= 1;
}
} else if (node.match( /^<\w[^>]*[^\/]>.*$/ )) {
indent = 1;
} else {
indent = 0;
}
var padding = '';
for (var i = 0; i < pad; i++) {
padding += ' ';
}
formatted += padding + node + '\r\n';
pad += indent;
});
return formatted;
}
Jag kallar sedan på funktionen så här:
jQuery('pre.formatted-xml').text(formatXml('<root><node1/></root>'));
Detta fungerar helt perfekt för mig, men medan jag skrev den tidigare funktionen tänkte jag att det måste finnas ett bättre sätt. Så min fråga är, känner du till något bättre sätt att formatera en XML-sträng snyggt på en HTML-sida? Alla JavaScript-ramverk och/eller plugins som kan göra jobbet är välkomna. Mitt enda krav är att detta ska göras på klientsidan.
Svar #1
Detta kan göras med inbyggda JavaScript-verktyg, utan tredjepartsbibliotek, genom att utvidga @Dimitre Novatchevs svar:
var prettifyXml = function(sourceXml)
{
var xmlDoc = new DOMParser().parseFromString(sourceXml, 'application/xml');
var xsltDoc = new DOMParser().parseFromString([
// describes how we want to modify the XML - indent everything
'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
' <xsl:strip-space elements="*"/>',
' <xsl:template match="para[content-style][not(text())]">', // change to just text() to strip space in text nodes
' <xsl:value-of select="normalize-space(.)"/>',
' </xsl:template>',
' <xsl:template match="node()|@*">',
' <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>',
' </xsl:template>',
' <xsl:output indent="yes"/>',
'</xsl:stylesheet>',
].join('\n'), 'application/xml');
var xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsltDoc);
var resultDoc = xsltProcessor.transformToDocument(xmlDoc);
var resultXml = new XMLSerializer().serializeToString(resultDoc);
return resultXml;
};
console.log(prettifyXml('<root><node/></root>'));
Utdata :
<root>
<node/>
</root>
JSFiddle
Observera, som påpekats av @jat255, är inte snygg utskrift med <xsl:output indent="yes"/> stödd av Firefox. Det verkar bara fungera i Chrome, Opera och förmodligen resten av WebKit-baserade webbläsare.
Svar #2
Från texten i frågan får jag intrycket att ett strängresultat förväntas, till skillnad från ett HTML-formaterat resultat.
Om detta är fallet, är det enklaste sättet att uppnå detta att bearbeta XML-dokumentet med identitetsomvandlingen och med en <xsl:output indent="yes"/>-instruktion:
<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>
När du använder denna omvandling på det tillhandahållna XML-dokumentet:
<root><node/></root>
de flesta XSLT-processorer (.NET XslCompiledTransform, Saxon 6.5.4 och Saxon 9.0.0.2, AltovaXML) ger det önskade resultatet:
<root>
<node />
</root>
Svar #3
Hittade denna tråd när jag hade ett liknande behov men jag förenklade OP:s kod på följande sätt:
function formatXml(xml, tab) { // tab = optional indent value, default is tab (\t)
var formatted = '', indent= '';
tab = tab || '\t';
xml.split(/>\s*</).forEach(function(node) {
if (node.match( /^\/\w/ )) indent = indent.substring(tab.length); // decrease indent by one 'tab'
formatted += indent + '<' + node + '>\r\n';
if (node.match( /^<?\w[^>]*[^\/]$/ )) indent += tab; // increase indent
});
return formatted.substring(1, formatted.length-3);
}
funkar för mig!
Svar #4
Mindre ändring av efnx clckclcks javascriptfunktion. Jag ändrade formateringen från mellanslag till tab, men viktigast av allt tillät jag texten att förbli på en rad:
var formatXml = this.formatXml = function (xml) {
var reg = /(>)\s*(<)(\/*)/g; // updated Mar 30, 2015
var wsexp = / *(.*) +\n/g;
var contexp = /(<.+>)(.+\n)/g;
xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
var pad = 0;
var formatted = '';
var lines = xml.split('\n');
var indent = 0;
var lastType = 'other';
// 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions
var transitions = {
'single->single': 0,
'single->closing': -1,
'single->opening': 0,
'single->other': 0,
'closing->single': 0,
'closing->closing': -1,
'closing->opening': 0,
'closing->other': 0,
'opening->single': 1,
'opening->closing': 0,
'opening->opening': 1,
'opening->other': 1,
'other->single': 0,
'other->closing': -1,
'other->opening': 0,
'other->other': 0
};
for (var i = 0; i < lines.length; i++) {
var ln = lines[i];
// Luca Viggiani 2017-07-03: handle optional <?xml ... ?> declaration
if (ln.match(/\s*<\?xml/)) {
formatted += ln + "\n";
continue;
}
// ---
var single = Boolean(ln.match(/<.+\/>/)); // is this line a single tag? ex. <br />
var closing = Boolean(ln.match(/<\/.+>/)); // is this a closing tag? ex. </a>
var opening = Boolean(ln.match(/<[^!].*>/)); // is this even a tag (that's not <!something>)
var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other';
var fromTo = lastType + '->' + type;
lastType = type;
var padding = '';
indent += transitions[fromTo];
for (var j = 0; j < indent; j++) {
padding += '\t';
}
if (fromTo == 'opening->closing')
formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; // substr removes line break (\n) from prev loop
else
formatted += padding + ln + '\n';
}
return formatted;
};
Svar #5
Personligen använder jag google-code-prettify med den här funktionen :
prettyPrintOne('<root><node1><root>', 'xml')
