browser_parser.js (5376B)
1 var util = require('../util'); 2 var Shape = require('../model/shape'); 3 4 function DomXmlParser() { } 5 6 DomXmlParser.prototype.parse = function(xml, shape) { 7 if (xml.replace(/^\s+/, '') === '') return {}; 8 9 var result, error; 10 try { 11 if (window.DOMParser) { 12 try { 13 var parser = new DOMParser(); 14 result = parser.parseFromString(xml, 'text/xml'); 15 } catch (syntaxError) { 16 throw util.error(new Error('Parse error in document'), 17 { 18 originalError: syntaxError, 19 code: 'XMLParserError', 20 retryable: true 21 }); 22 } 23 24 if (result.documentElement === null) { 25 throw util.error(new Error('Cannot parse empty document.'), 26 { 27 code: 'XMLParserError', 28 retryable: true 29 }); 30 } 31 32 var isError = result.getElementsByTagName('parsererror')[0]; 33 if (isError && (isError.parentNode === result || 34 isError.parentNode.nodeName === 'body' || 35 isError.parentNode.parentNode === result || 36 isError.parentNode.parentNode.nodeName === 'body')) { 37 var errorElement = isError.getElementsByTagName('div')[0] || isError; 38 throw util.error(new Error(errorElement.textContent || 'Parser error in document'), 39 { 40 code: 'XMLParserError', 41 retryable: true 42 }); 43 } 44 } else if (window.ActiveXObject) { 45 result = new window.ActiveXObject('Microsoft.XMLDOM'); 46 result.async = false; 47 48 if (!result.loadXML(xml)) { 49 throw util.error(new Error('Parse error in document'), 50 { 51 code: 'XMLParserError', 52 retryable: true 53 }); 54 } 55 } else { 56 throw new Error('Cannot load XML parser'); 57 } 58 } catch (e) { 59 error = e; 60 } 61 62 if (result && result.documentElement && !error) { 63 var data = parseXml(result.documentElement, shape); 64 var metadata = result.getElementsByTagName('ResponseMetadata')[0]; 65 if (metadata) { 66 data.ResponseMetadata = parseXml(metadata, {}); 67 } 68 return data; 69 } else if (error) { 70 throw util.error(error || new Error(), {code: 'XMLParserError', retryable: true}); 71 } else { // empty xml document 72 return {}; 73 } 74 }; 75 76 function parseXml(xml, shape) { 77 if (!shape) shape = {}; 78 switch (shape.type) { 79 case 'structure': return parseStructure(xml, shape); 80 case 'map': return parseMap(xml, shape); 81 case 'list': return parseList(xml, shape); 82 case undefined: case null: return parseUnknown(xml); 83 default: return parseScalar(xml, shape); 84 } 85 } 86 87 function parseStructure(xml, shape) { 88 var data = {}; 89 if (xml === null) return data; 90 91 util.each(shape.members, function(memberName, memberShape) { 92 if (memberShape.isXmlAttribute) { 93 if (Object.prototype.hasOwnProperty.call(xml.attributes, memberShape.name)) { 94 var value = xml.attributes[memberShape.name].value; 95 data[memberName] = parseXml({textContent: value}, memberShape); 96 } 97 } else { 98 var xmlChild = memberShape.flattened ? xml : 99 xml.getElementsByTagName(memberShape.name)[0]; 100 if (xmlChild) { 101 data[memberName] = parseXml(xmlChild, memberShape); 102 } else if (!memberShape.flattened && memberShape.type === 'list') { 103 data[memberName] = memberShape.defaultValue; 104 } 105 } 106 }); 107 108 return data; 109 } 110 111 function parseMap(xml, shape) { 112 var data = {}; 113 var xmlKey = shape.key.name || 'key'; 114 var xmlValue = shape.value.name || 'value'; 115 var tagName = shape.flattened ? shape.name : 'entry'; 116 117 var child = xml.firstElementChild; 118 while (child) { 119 if (child.nodeName === tagName) { 120 var key = child.getElementsByTagName(xmlKey)[0].textContent; 121 var value = child.getElementsByTagName(xmlValue)[0]; 122 data[key] = parseXml(value, shape.value); 123 } 124 child = child.nextElementSibling; 125 } 126 return data; 127 } 128 129 function parseList(xml, shape) { 130 var data = []; 131 var tagName = shape.flattened ? shape.name : (shape.member.name || 'member'); 132 133 var child = xml.firstElementChild; 134 while (child) { 135 if (child.nodeName === tagName) { 136 data.push(parseXml(child, shape.member)); 137 } 138 child = child.nextElementSibling; 139 } 140 return data; 141 } 142 143 function parseScalar(xml, shape) { 144 if (xml.getAttribute) { 145 var encoding = xml.getAttribute('encoding'); 146 if (encoding === 'base64') { 147 shape = new Shape.create({type: encoding}); 148 } 149 } 150 151 var text = xml.textContent; 152 if (text === '') text = null; 153 if (typeof shape.toType === 'function') { 154 return shape.toType(text); 155 } else { 156 return text; 157 } 158 } 159 160 function parseUnknown(xml) { 161 if (xml === undefined || xml === null) return ''; 162 163 // empty object 164 if (!xml.firstElementChild) { 165 if (xml.parentNode.parentNode === null) return {}; 166 if (xml.childNodes.length === 0) return ''; 167 else return xml.textContent; 168 } 169 170 // object, parse as structure 171 var shape = {type: 'structure', members: {}}; 172 var child = xml.firstElementChild; 173 while (child) { 174 var tag = child.nodeName; 175 if (Object.prototype.hasOwnProperty.call(shape.members, tag)) { 176 // multiple tags of the same name makes it a list 177 shape.members[tag].type = 'list'; 178 } else { 179 shape.members[tag] = {name: tag}; 180 } 181 child = child.nextElementSibling; 182 } 183 return parseStructure(xml, shape); 184 } 185 186 module.exports = DomXmlParser;