Created
July 10, 2015 10:37
-
-
Save rplantiko/b92f0231c4e149bf75aa to your computer and use it in GitHub Desktop.
XML beautifier with attribute alignment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* global process */ | |
// A simple xml beautifier, based on the xml2js parser | |
// - align attribute names (this is what xmlbuilder can't do) | |
// - indent by 2 spaces | |
// Don't expect too much: | |
// xml2js can't handle mixed element content: | |
// <a>b<c/>d</a> is equal to <a>bd<c/></a> in the eyes of xml2js | |
(function(){ | |
var fs = require('fs') | |
var xml2js = require('xml2js') | |
if (process.argv.length < 3) { | |
process.stderr.write("Please specify source xml file name") | |
process.exit(1) | |
} | |
fs.readFile( process.argv[2], 'utf8', onSuccess( function(data) { | |
var parser = new xml2js.Parser() | |
parser.parseString(data, onSuccess( function(xjson) { | |
var lines = beautify(xjson) | |
process.stdout.write(lines.join('\n')) | |
})) | |
})) | |
function onSuccess(f) { | |
return function(err,data) { | |
if (err) console.dir(err) | |
else f(data) | |
} | |
} | |
function beautify(xjson) { | |
var indent = "" | |
var lines = [] | |
traverse(xjson) | |
return lines | |
function traverse(node, name ) { | |
if (name === undefined) return handleRoot() | |
if (typeof node == "string") return handleTextContent() | |
if (node instanceof Array) return handleArray() | |
handleOpenElement() | |
handleElementContent() | |
handleCloseElement() | |
function handleRoot() { | |
console.assert(typeof node == "object", "Call beautify with a JSON object") | |
var keys = Object.keys(node) | |
console.assert(keys.length == 1, "An XML object must have exactly 1 root element") | |
traverse( node[keys[0]], keys[0] ) | |
} | |
function handleOpenElement() { | |
var line = indent + "<" + name | |
if (node.hasOwnProperty("$")) handleAttributes() | |
line += ">" | |
lines.push(line) | |
indent += " " | |
function handleAttributes() { | |
line += " " | |
var attindent = line.replace(/./g," ") | |
var numatts = Object.keys(node.$).length | |
Object.keys(node.$).forEach( function(attname,i) { | |
var att = attname + '="' + node.$[attname].replace(/"/g,'"') + '"' | |
line += att | |
if (i==numatts-1) return | |
lines.push(line) | |
line = attindent | |
}) | |
} | |
} | |
function handleElementContent() { | |
Object.keys(node) | |
.filter( function(key) { return key!='$' }) | |
.forEach( function(key) { | |
var y = node[key] | |
traverse(y,key) | |
}) | |
} | |
function handleTextContent() { | |
if (node) lines.push( indent + node ) | |
} | |
function handleCloseElement() { | |
indent = indent.slice(0,-2) | |
lines.push( indent + "</" + name + ">" ) | |
} | |
function handleArray() { | |
// empty element | |
if ( (node.length == 1) && (node[0] === '')) { | |
lines.push(indent+'<'+name+'/>') | |
} | |
// xml2js way of denoting successive elements of the same element name | |
node.forEach( | |
function(item) { traverse(item,name) } | |
) | |
} | |
} | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment