123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- var AWS = require('../core');
- var util = AWS.util;
- var Shape = AWS.Model.Shape;
- var xml2js = require('xml2js');
- /**
- * @api private
- */
- var options = { // options passed to xml2js parser
- explicitCharkey: false, // undocumented
- trim: false, // trim the leading/trailing whitespace from text nodes
- normalize: false, // trim interior whitespace inside text nodes
- explicitRoot: false, // return the root node in the resulting object?
- emptyTag: null, // the default value for empty nodes
- explicitArray: true, // always put child nodes in an array
- ignoreAttrs: false, // ignore attributes, only create text nodes
- mergeAttrs: false, // merge attributes and child elements
- validator: null // a callable validator
- };
- function NodeXmlParser() { }
- NodeXmlParser.prototype.parse = function(xml, shape) {
- shape = shape || {};
- var result = null;
- var error = null;
- var parser = new xml2js.Parser(options);
- parser.parseString(xml, function (e, r) {
- error = e;
- result = r;
- });
- if (result) {
- var data = parseXml(result, shape);
- if (result.ResponseMetadata) {
- data.ResponseMetadata = parseXml(result.ResponseMetadata[0], {});
- }
- return data;
- } else if (error) {
- throw util.error(error, {code: 'XMLParserError', retryable: true});
- } else { // empty xml document
- return parseXml({}, shape);
- }
- };
- function parseXml(xml, 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) {
- var xmlName = memberShape.name;
- if (Object.prototype.hasOwnProperty.call(xml, xmlName) && Array.isArray(xml[xmlName])) {
- var xmlChild = xml[xmlName];
- if (!memberShape.flattened) xmlChild = xmlChild[0];
- data[memberName] = parseXml(xmlChild, memberShape);
- } else if (memberShape.isXmlAttribute &&
- xml.$ && Object.prototype.hasOwnProperty.call(xml.$, xmlName)) {
- data[memberName] = parseScalar(xml.$[xmlName], memberShape);
- } else if (memberShape.type === 'list' && !shape.api.xmlNoDefaultLists) {
- data[memberName] = memberShape.defaultValue;
- }
- });
- return data;
- }
- function parseMap(xml, shape) {
- var data = {};
- if (xml === null) return data;
- var xmlKey = shape.key.name || 'key';
- var xmlValue = shape.value.name || 'value';
- var iterable = shape.flattened ? xml : xml.entry;
- if (Array.isArray(iterable)) {
- util.arrayEach(iterable, function(child) {
- data[child[xmlKey][0]] = parseXml(child[xmlValue][0], shape.value);
- });
- }
- return data;
- }
- function parseList(xml, shape) {
- var data = [];
- var name = shape.member.name || 'member';
- if (shape.flattened) {
- util.arrayEach(xml, function(xmlChild) {
- data.push(parseXml(xmlChild, shape.member));
- });
- } else if (xml && Array.isArray(xml[name])) {
- util.arrayEach(xml[name], function(child) {
- data.push(parseXml(child, shape.member));
- });
- }
- return data;
- }
- function parseScalar(text, shape) {
- if (text && text.$ && text.$.encoding === 'base64') {
- shape = new Shape.create({type: text.$.encoding});
- }
- if (text && text._) text = text._;
- if (typeof shape.toType === 'function') {
- return shape.toType(text);
- } else {
- return text;
- }
- }
- function parseUnknown(xml) {
- if (xml === undefined || xml === null) return '';
- if (typeof xml === 'string') return xml;
- // parse a list
- if (Array.isArray(xml)) {
- var arr = [];
- for (i = 0; i < xml.length; i++) {
- arr.push(parseXml(xml[i], {}));
- }
- return arr;
- }
- // empty object
- var keys = Object.keys(xml), i;
- if (keys.length === 0 || (keys.length === 1 && keys[0] === '$')) {
- return {};
- }
- // object, parse as structure
- var data = {};
- for (i = 0; i < keys.length; i++) {
- var key = keys[i], value = xml[key];
- if (key === '$') continue;
- if (value.length > 1) { // this member is a list
- data[key] = parseList(value, {member: {}});
- } else { // this member is a single item
- data[key] = parseXml(value[0], {});
- }
- }
- return data;
- }
- /**
- * @api private
- */
- module.exports = NodeXmlParser;
|