-
-
Save sente/1083506 to your computer and use it in GitHub Desktop.
The MIT License (MIT) | |
Copyright (c) 2016 Stuart Powers | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
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; | |
} | |
xml_raw = '<foo><bar><baz>blahblah</baz><baz>tralala</baz></bar></foo>'; | |
xml_formatted = formatXml(xml_raw); | |
xml_escaped = xml_formatted.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/ /g, ' ').replace(/\n/g,'<br />'); | |
var mydiv = document.createElement('div'); | |
mydiv.innerHTML = xml_escaped; | |
document.body.appendChild(mydiv); | |
<html> | |
<head> | |
<title>Javascript xml pretty print - Stuart Powers</title> | |
<script src="http://bit.ly/jqymin"></script> | |
<style> | |
textarea { | |
width: 80%; | |
height: 50%; | |
overflow-x: scroll; | |
overflow-y: scroll; | |
display: block; | |
border: 1px solid black; | |
padding: 5px; | |
margin: 5px; | |
} | |
</style> | |
<script> | |
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; | |
} | |
$(function(){ | |
var url = "http://careers.stackoverflow.com/jobs/feed?searchTerm=python&location=02144&range=30"; | |
$.ajax({ | |
url: url, | |
dataType:"text", | |
beforeSend:function(){$('.info').append($('<p>requesting: '+url+'</p>'));}, | |
error:function(){$('.info').append($('<p>error! '+url+'</p>'));}, | |
success: function(data) { | |
$('.unformatted').text(data); | |
} | |
}); | |
$.ajax({ | |
url: url, | |
dataType:"text", | |
beforeSend:function(){ | |
$('.info2').append($('<p>requesting '+url+'</p>')); | |
$('.info2').append($('<p>and formatting the response!')); | |
}, | |
error:function(){$('.info2').append($('<p>error! '+url+'</p>'));}, | |
success: function(data) { | |
xml_neat = formatXml(data); | |
$('.formatted').text(xml_neat); | |
} | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
<code> | |
Also available <a href="http://sente.cc/misc/javascript_xml_pretty_print.html"> | |
http://sente.cc/misc/javascript_xml_pretty_print.html | |
</a> | |
</code> | |
<pre class="info"></pre> | |
<h3>unformatted</h3> | |
<textarea class="unformatted"></textarea> | |
<h3>formatted</h3> | |
<textarea class="formatted"></textarea> | |
<body> | |
</html> |
Thanks for the code.
Here's an adapted ES6 variant:
formatXml(xml) {
const PADDING = ' '.repeat(2); // set desired indent size here
const reg = /(>)(<)(\/*)/g;
let pad = 0;
xml = xml.replace(reg, '$1\r\n$2$3');
return xml.split('\r\n').map((node, index) => {
let indent = 0;
if (node.match(/.+<\/\w[^>]*>$/)) {
indent = 0;
} else if (node.match(/^<\/\w/) && pad > 0) {
pad -= 1;
} else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
indent = 1;
} else {
indent = 0;
}
pad += indent;
return PADDING.repeat(pad - indent) + node;
}).join('\r\n');
}
ES6 variant works for me. Thanks!
@grubersjoe
js lint fails with this message:
Unnecessary escape character: \/ no-useless-escape
so I used [^/]
in last node.match
function
Many Thanks,, works perfect!!
did you try script on bad formed xml like
<feed xmlns="http://www.w3.org/2005/Atom"
need="urgent"> <title type="general" sub="sample">Example Feed</title>
<subtitle><![CDATA[minor subtitle <<< ]]></subtitle>
<author nn="1" order="2" case="now"><name>John Doe</name><email>johndoe@example.com</email>
</author> <entry><title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03" />
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated><summary>Some text.</summary>
</entry> </feed>
? it does not work for me
@grubersjoe
Many thanks!
@ sente
Wow, so cool, thanks!
<simple-value><![CDATA[部门
Dept]]>
after format xml, it will be follow result, have many space char before <![CDATA
i had try, modify ,
var reg = /(>)(<)([^!])(/*)/g;
thanks \o
Good work - although I must point out that it doesn't touch existing whitespace indentation, with hilarious consequences.
Thanks for the code.
Here's an adapted ES6 variant:
formatXml(xml) { const PADDING = ' '.repeat(2); // set desired indent size here const reg = /(>)(<)(\/*)/g; let pad = 0; xml = xml.replace(reg, '$1\r\n$2$3'); return xml.split('\r\n').map((node, index) => { let indent = 0; if (node.match(/.+<\/\w[^>]*>$/)) { indent = 0; } else if (node.match(/^<\/\w/) && pad > 0) { pad -= 1; } else if (node.match(/^<\w[^>]*[^\/]>.*$/)) { indent = 1; } else { indent = 0; } pad += indent; return PADDING.repeat(pad - indent) + node; }).join('\r\n'); }
Thanks for the ES6 version @grubersjoe ,a small addition though for handling newlines and existing whitespace between tags(as pointed out by @brennanyoung):
formatXml(xml) {
// Remove all the newlines and then remove all the spaces between tags
xml = xml.replace(/(\r\n|\n|\r)/gm, " ").replace(/>\s+</g,'><');
const PADDING = ' '.repeat(4); // set desired indent size here
const reg = /(>)(<)(\/*)/g;
let pad = 0;
xml = xml.replace(reg, '$1\r\n$2$3');
return xml.split('\r\n').map((node, index) => {
let indent = 0;
if (node.match(/.+<\/\w[^>]*>$/)) {
indent = 0;
} else if (node.match(/^<\/\w/) && pad > 0) {
pad -= 1;
} else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
indent = 1;
} else {
indent = 0;
}
pad += indent;
return PADDING.repeat(pad - indent) + node;
}).join('\r\n');
}
I'm not sure if the latest versions of FF added more constraints, I'm getting "Toot much recursion" from formatXml()
A slight mismatch in one of the regular expressions needs to be: node.match(/^<[\w^>]*[^\/]>.*$/))
. Merging everyone's updates, here's what I've been using:
/**
* Prettifies the tab indentation of given XML string
*
* @param xml string - The XML to clean
* @return string - Prettified XML string
*/
static prettify(xml: String) {
let pad = 0;
const padding = '\u0020'.repeat(4); // set desired indent size here
xml = xml.replace(/(\r\n|\n|\r)/gm, '\u0020').replace(/>\s+</g,'><');
xml = xml.replace(/(>)(<)(\/*)/g, '$1\r\n$2$3');
return xml.split('\r\n').map((node, index) => { //XML elements now split into lines
let indent = 0;
if (node.match(/.+<\/\w[^>]*>$/)) {
indent = 0;
} else if (node.match(/^<\/\w/) && pad > 0) {
pad -= 1;
} else if (node.match(/^<[\w^>]*[^\/]>.*$/)) {
indent = 1;
} else {
indent = 0;
}
pad += indent;
return padding.repeat(pad - indent) + node;
}).join('\r\n');
}
jlyk: if (node.match(/.+<\/\w[^>]*>$/)) {
- this is extremely slow on big rows.
not for production use for sure ;) - DannyDainton/newman-reporter-htmlextra#428 (comment)
@Risord Indeed, that regular expression should be
/^<\w([^>]*[^\/])?>.*$/