Last active
April 17, 2018 14:27
-
-
Save azappella/a9f5bfe0c3318f5249b5f2125dfd8973 to your computer and use it in GitHub Desktop.
XML Parser & Transformer
This file contains 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
// Source: Andrew Stewart | |
// https://andrew.stwrt.ca/posts/js-xml-parsing/) | |
// get your XML in a text format | |
// var xmlText = getXMLString(); | |
// use the DOMParser browser API to convert text to a Document | |
// var XML = new DOMParser().parseFromString(xml, "text/xml"); | |
// and then use #parse to convert it to a JS object | |
// var obj = parse(XML); | |
// flattens an object (recursively!), similarly to Array#flatten | |
// e.g. flatten({ a: { b: { c: "hello!" } } }); // => "hello!" | |
function flatten(object) { | |
var check = _.isPlainObject(object) && _.size(object) === 1; | |
return check ? flatten(_.values(object)[0]) : object; | |
} | |
function parse(xml) { | |
var data = {}; | |
var isText = xml.nodeType === 3, | |
isElement = xml.nodeType === 1, | |
body = xml.textContent && xml.textContent.trim(), | |
hasChildren = xml.children && xml.children.length, | |
hasAttributes = xml.attributes && xml.attributes.length; | |
// if it's text just return it | |
if (isText) { return xml.nodeValue.trim(); } | |
// if it doesn't have any children or attributes, just return the contents | |
if (!hasChildren && !hasAttributes) { return body; } | |
// if it doesn't have children but _does_ have body content, we'll use that | |
if (!hasChildren && body.length) { data.text = body; } | |
// if it's an element with attributes, add them to data.attributes | |
if (isElement && hasAttributes) { | |
data.attributes = _.reduce(xml.attributes, function(obj, name, id) { | |
var attr = xml.attributes.item(id); | |
obj[attr.name] = attr.value; | |
return obj; | |
}, {}); | |
} | |
// recursively call #parse over children, adding results to data | |
_.each(xml.children, function(child) { | |
var name = child.nodeName; | |
// if we've not come across a child with this nodeType, add it as an object | |
// and return here | |
if (!_.has(data, name)) { | |
data[name] = parse(child); | |
return; | |
} | |
// if we've encountered a second instance of the same nodeType, make our | |
// representation of it an array | |
if (!_.isArray(data[name])) { data[name] = [data[name]]; } | |
// and finally, append the new child | |
data[name].push(parse(child)); | |
}); | |
// if we can, let's fold some attributes into the body | |
_.each(data.attributes, function(value, key) { | |
if (data[key] != null) { return; } | |
data[key] = value; | |
delete data.attributes[key]; | |
}); | |
// if data.attributes is now empty, get rid of it | |
if (_.isEmpty(data.attributes)) { delete data.attributes; } | |
// simplify to reduce number of final leaf nodes and return | |
return flatten(data); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment