# Lambda Function - xml to json ## from_xml.js ``` /** * The fromXML() method parses an XML string, constructing the JavaScript * value or object described by the string. * * @function fromXML * @param text {String} The string to parse as XML * @param [reviver] {Function} If a function, prescribes how the value * originally produced by parsing is transformed, before being returned. * @returns {Object} */ var fromXML; (function(exports) { var UNESCAPE = { "&amp;": "&", "&lt;": "<", "&gt;": ">", "&apos;": "'", "&quot;": '"' }; var ATTRIBUTE_KEY = "@"; var CHILD_NODE_KEY = "#"; exports.fromXML = fromXML = _fromXML; function _fromXML(text, reviver) { return toObject(parseXML(text), reviver); } function parseXML(text) { var list = String.prototype.split.call(text, /<([^!<>?](?:'[\S\s]*?'|"[\S\s]*?"|[^'"<>])*|!(?:--[\S\s]*?--|\[[^\[\]'"<>]+\[[\S\s]*?]]|DOCTYPE[^\[<>]*?\[[\S\s]*?]|(?:ENTITY[^"<>]*?"[\S\s]*?")?[\S\s]*?)|\?[\S\s]*?\?)>/); var length = list.length; // root element var root = {f: []}; var elem = root; // dom tree stack var stack = []; for (var i = 0; i < length;) { // text node var str = list[i++]; if (str) appendText(str); // child node var tag = list[i++]; if (tag) parseNode(tag); } return root; function parseNode(tag) { var tagLength = tag.length; var firstChar = tag[0]; if (firstChar === "/") { // close tag var closed = tag.replace(/^\/|[\s\/].*$/g, "").toLowerCase(); while (stack.length) { var tagName = elem.n && elem.n.toLowerCase(); elem = stack.pop(); if (tagName === closed) break; } } else if (firstChar === "?") { // XML declaration appendChild({n: "?", r: tag.substr(1, tagLength - 2)}); } else if (firstChar === "!") { if (tag.substr(1, 7) === "[CDATA[" && tag.substr(-2) === "]]") { // CDATA section appendText(tag.substr(8, tagLength - 10)); } else { // comment appendChild({n: "!", r: tag.substr(1)}); } } else { var child = openTag(tag); appendChild(child); if (tag[tagLength - 1] === "/") { child.c = 1; // emptyTag } else { stack.push(elem); // openTag elem = child; } } } function appendChild(child) { elem.f.push(child); } function appendText(str) { str = removeSpaces(str); if (str) appendChild(unescapeXML(str)); } } function openTag(tag) { var elem = {f: []}; tag = tag.replace(/\s*\/?$/, ""); var pos = tag.search(/[\s='"\/]/); if (pos < 0) { elem.n = tag; } else { elem.n = tag.substr(0, pos); elem.t = tag.substr(pos); } return elem; } function parseAttribute(elem, reviver) { if (!elem.t) return; var list = elem.t.split(/([^\s='"]+(?:\s*=\s*(?:'[\S\s]*?'|"[\S\s]*?"|[^\s'"]*))?)/); var length = list.length; var attributes, val; for (var i = 0; i < length; i++) { var str = removeSpaces(list[i]); if (!str) continue; if (!attributes) { attributes = {}; } var pos = str.indexOf("="); if (pos < 0) { // bare attribute str = ATTRIBUTE_KEY + str; val = null; } else { // attribute key/value pair val = str.substr(pos + 1).replace(/^\s+/, ""); str = ATTRIBUTE_KEY + str.substr(0, pos).replace(/\s+$/, ""); // quote: foo="FOO" bar='BAR' var firstChar = val[0]; var lastChar = val[val.length - 1]; if (firstChar === lastChar && (firstChar === "'" || firstChar === '"')) { val = val.substr(1, val.length - 2); } val = unescapeXML(val); } if (reviver) { val = reviver(str, val); } addObject(attributes, str, val); } return attributes; } function removeSpaces(str) { return str && str.replace(/^\s+|\s+$/g, ""); } function unescapeXML(str) { return str.replace(/(&(?:lt|gt|amp|apos|quot|#(?:\d{1,6}|x[0-9a-fA-F]{1,5}));)/g, function(str) { if (str[1] === "#") { var code = (str[2] === "x") ? parseInt(str.substr(3), 16) : parseInt(str.substr(2), 10); if (code > -1) return String.fromCharCode(code); } return UNESCAPE[str] || str; }); } function toObject(elem, reviver) { if ("string" === typeof elem) return elem; var raw = elem.r; if (raw) return raw; var attributes = parseAttribute(elem, reviver); var object; var childList = elem.f; var childLength = childList.length; if (attributes || childLength > 1) { // merge attributes and child nodes object = attributes || {}; childList.forEach(function(child) { if ("string" === typeof child) { addObject(object, CHILD_NODE_KEY, child); } else { addObject(object, child.n, toObject(child, reviver)); } }); } else if (childLength) { // the node has single child node but no attribute var child = childList[0]; object = toObject(child, reviver); if (child.n) { var wrap = {}; wrap[child.n] = object; object = wrap; } } else { // the node has no attribute nor child node object = elem.c ? null : ""; } if (reviver) { object = reviver(elem.n || "", object); } return object; } function addObject(object, key, val) { if ("undefined" === typeof val) return; var prev = object[key]; if (prev instanceof Array) { prev.push(val); } else if (key in object) { object[key] = [prev, val]; } else { object[key] = val; } } })(typeof exports === "object" && exports || {}); ```