Backend half
This commit is contained in:
+163
@@ -0,0 +1,163 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user