123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- var util = require('../util');
- var Shape = require('../model/shape');
- function DomXmlParser() { }
- DomXmlParser.prototype.parse = function(xml, shape) {
- if (xml.replace(/^\s+/, '') === '') return {};
- var result, error;
- try {
- if (window.DOMParser) {
- try {
- var parser = new DOMParser();
- result = parser.parseFromString(xml, 'text/xml');
- } catch (syntaxError) {
- throw util.error(new Error('Parse error in document'),
- {
- originalError: syntaxError,
- code: 'XMLParserError',
- retryable: true
- });
- }
- if (result.documentElement === null) {
- throw util.error(new Error('Cannot parse empty document.'),
- {
- code: 'XMLParserError',
- retryable: true
- });
- }
- var isError = result.getElementsByTagName('parsererror')[0];
- if (isError && (isError.parentNode === result ||
- isError.parentNode.nodeName === 'body' ||
- isError.parentNode.parentNode === result ||
- isError.parentNode.parentNode.nodeName === 'body')) {
- var errorElement = isError.getElementsByTagName('div')[0] || isError;
- throw util.error(new Error(errorElement.textContent || 'Parser error in document'),
- {
- code: 'XMLParserError',
- retryable: true
- });
- }
- } else if (window.ActiveXObject) {
- result = new window.ActiveXObject('Microsoft.XMLDOM');
- result.async = false;
- if (!result.loadXML(xml)) {
- throw util.error(new Error('Parse error in document'),
- {
- code: 'XMLParserError',
- retryable: true
- });
- }
- } else {
- throw new Error('Cannot load XML parser');
- }
- } catch (e) {
- error = e;
- }
- if (result && result.documentElement && !error) {
- var data = parseXml(result.documentElement, shape);
- var metadata = getElementByTagName(result.documentElement, 'ResponseMetadata');
- if (metadata) {
- data.ResponseMetadata = parseXml(metadata, {});
- }
- return data;
- } else if (error) {
- throw util.error(error || new Error(), {code: 'XMLParserError', retryable: true});
- } else { // empty xml document
- return {};
- }
- };
- function getElementByTagName(xml, tag) {
- var elements = xml.getElementsByTagName(tag);
- for (var i = 0, iLen = elements.length; i < iLen; i++) {
- if (elements[i].parentNode === xml) {
- return elements[i];
- }
- }
- }
- function parseXml(xml, shape) {
- if (!shape) shape = {};
- switch (shape.type) {
- case 'structure': return parseStructure(xml, shape);
- case 'map': return parseMap(xml, shape);
- case 'list': return parseList(xml, shape);
- case undefined: case null: return parseUnknown(xml);
- default: return parseScalar(xml, shape);
- }
- }
- function parseStructure(xml, shape) {
- var data = {};
- if (xml === null) return data;
- util.each(shape.members, function(memberName, memberShape) {
- if (memberShape.isXmlAttribute) {
- if (Object.prototype.hasOwnProperty.call(xml.attributes, memberShape.name)) {
- var value = xml.attributes[memberShape.name].value;
- data[memberName] = parseXml({textContent: value}, memberShape);
- }
- } else {
- var xmlChild = memberShape.flattened ? xml :
- getElementByTagName(xml, memberShape.name);
- if (xmlChild) {
- data[memberName] = parseXml(xmlChild, memberShape);
- } else if (
- !memberShape.flattened &&
- memberShape.type === 'list' &&
- !shape.api.xmlNoDefaultLists) {
- data[memberName] = memberShape.defaultValue;
- }
- }
- });
- return data;
- }
- function parseMap(xml, shape) {
- var data = {};
- var xmlKey = shape.key.name || 'key';
- var xmlValue = shape.value.name || 'value';
- var tagName = shape.flattened ? shape.name : 'entry';
- var child = xml.firstElementChild;
- while (child) {
- if (child.nodeName === tagName) {
- var key = getElementByTagName(child, xmlKey).textContent;
- var value = getElementByTagName(child, xmlValue);
- data[key] = parseXml(value, shape.value);
- }
- child = child.nextElementSibling;
- }
- return data;
- }
- function parseList(xml, shape) {
- var data = [];
- var tagName = shape.flattened ? shape.name : (shape.member.name || 'member');
- var child = xml.firstElementChild;
- while (child) {
- if (child.nodeName === tagName) {
- data.push(parseXml(child, shape.member));
- }
- child = child.nextElementSibling;
- }
- return data;
- }
- function parseScalar(xml, shape) {
- if (xml.getAttribute) {
- var encoding = xml.getAttribute('encoding');
- if (encoding === 'base64') {
- shape = new Shape.create({type: encoding});
- }
- }
- var text = xml.textContent;
- if (text === '') text = null;
- if (typeof shape.toType === 'function') {
- return shape.toType(text);
- } else {
- return text;
- }
- }
- function parseUnknown(xml) {
- if (xml === undefined || xml === null) return '';
- // empty object
- if (!xml.firstElementChild) {
- if (xml.parentNode.parentNode === null) return {};
- if (xml.childNodes.length === 0) return '';
- else return xml.textContent;
- }
- // object, parse as structure
- var shape = {type: 'structure', members: {}};
- var child = xml.firstElementChild;
- while (child) {
- var tag = child.nodeName;
- if (Object.prototype.hasOwnProperty.call(shape.members, tag)) {
- // multiple tags of the same name makes it a list
- shape.members[tag].type = 'list';
- } else {
- shape.members[tag] = {name: tag};
- }
- child = child.nextElementSibling;
- }
- return parseStructure(xml, shape);
- }
- /**
- * @api private
- */
- module.exports = DomXmlParser;
|