mirror of
https://github.com/amark/gun.git
synced 2025-06-11 16:46:43 +00:00
171 lines
5.0 KiB
JavaScript
171 lines
5.0 KiB
JavaScript
var AWS = require('../core');
|
|
var inherit = AWS.util.inherit;
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
AWS.XML.Parser = inherit({
|
|
constructor: function XMLParser(rules) {
|
|
this.rules = (rules || {}).members || {};
|
|
},
|
|
|
|
parse: function parse(xml) {
|
|
if (xml.replace(/^\s+/, '') === '') return {};
|
|
|
|
var result, error;
|
|
try {
|
|
if (window.DOMParser) {
|
|
var parser = new DOMParser();
|
|
result = parser.parseFromString(xml, 'text/xml');
|
|
|
|
if (result.documentElement === null) {
|
|
throw new Error('Cannot parse empty document.');
|
|
}
|
|
|
|
var isError = result.getElementsByTagName('parsererror')[0];
|
|
if (isError && (isError.parentNode === result ||
|
|
isError.parentNode.nodeName === 'body')) {
|
|
throw new Error(isError.getElementsByTagName('div')[0].textContent);
|
|
}
|
|
} else if (window.ActiveXObject) {
|
|
result = new window.ActiveXObject('Microsoft.XMLDOM');
|
|
result.async = false;
|
|
|
|
if (!result.loadXML(xml)) {
|
|
throw new Error('Parse error in document');
|
|
}
|
|
} else {
|
|
throw new Error('Cannot load XML parser');
|
|
}
|
|
} catch (e) {
|
|
error = e;
|
|
}
|
|
|
|
if (result && result.documentElement && !error) {
|
|
return this.parseStructure(result.documentElement, this.rules);
|
|
} else if (error) {
|
|
throw AWS.util.error(error || new Error(), {code: 'XMLParserError'});
|
|
} else { // empty xml document
|
|
return {};
|
|
}
|
|
},
|
|
|
|
parseStructure: function parseStructure(structure, rules) {
|
|
var data = {};
|
|
|
|
// force array members to always be present
|
|
AWS.util.each.call(this, rules, function(memberName, memberRules) {
|
|
if (memberRules.type === 'list') {
|
|
data[memberRules.name || memberName] = [];
|
|
}
|
|
});
|
|
|
|
for (var j = 0; j < structure.attributes.length; j++) {
|
|
var attr = structure.attributes[j];
|
|
var attrRule = rules[attr.name];
|
|
if (attrRule) {
|
|
var value = this.parseMember({ textContent: attr.value }, attrRule);
|
|
data[attrRule.name || attr.name] = value;
|
|
}
|
|
}
|
|
|
|
var child = structure.firstElementChild;
|
|
while (child) {
|
|
var rule = rules[child.nodeName] || {};
|
|
var key = rule.name || child.nodeName;
|
|
var inData = rule.flattened ? data[key] : null;
|
|
data[key] = this.parseMember(child, rule, inData);
|
|
child = child.nextElementSibling;
|
|
}
|
|
|
|
return data;
|
|
},
|
|
|
|
parseMap: function parseMap(map, rules, data) {
|
|
data = data || {};
|
|
var keyRules = rules.keys || {};
|
|
var valueRules = rules.members || {};
|
|
var keyName = keyRules.name || 'key';
|
|
var valueName = valueRules.name || 'value';
|
|
|
|
function run(item) {
|
|
var key = item.getElementsByTagName(keyName)[0].textContent;
|
|
var value = item.getElementsByTagName(valueName)[0];
|
|
value = this.parseMember(value, valueRules);
|
|
data[key] = value;
|
|
}
|
|
|
|
if (rules.flattened) {
|
|
run.call(this, map);
|
|
} else {
|
|
var child = map.firstElementChild;
|
|
while (child) {
|
|
run.call(this, child);
|
|
child = child.nextElementSibling;
|
|
}
|
|
}
|
|
return data;
|
|
},
|
|
|
|
parseList: function parseList(list, rules, data) {
|
|
data = data || [];
|
|
var memberRules = rules.members || {};
|
|
var memberName = memberRules.name || 'member';
|
|
if (rules.flattened) {
|
|
data.push(this.parseMember(list, memberRules));
|
|
} else {
|
|
var child = list.firstElementChild;
|
|
while (child) {
|
|
if (child.nodeName === memberName) {
|
|
data.push(this.parseMember(child, memberRules));
|
|
}
|
|
child = child.nextElementSibling;
|
|
}
|
|
}
|
|
return data;
|
|
},
|
|
|
|
parseMember: function parseMember(member, rules, data) {
|
|
if (!rules.type) {
|
|
if (member.childElementCount > 0) {
|
|
rules.type = 'structure';
|
|
} else {
|
|
rules.type = 'string';
|
|
}
|
|
}
|
|
|
|
if (rules.type === 'structure') {
|
|
return this.parseStructure(member, rules.members || {}, data);
|
|
} else if (rules.type === 'list') {
|
|
return this.parseList(member, rules, data);
|
|
} else if (rules.type === 'map') {
|
|
return this.parseMap(member, rules, data);
|
|
}
|
|
|
|
if (rules.type === 'string') {
|
|
if (member.attributes && member.attributes.encoding &&
|
|
member.attributes.encoding.value === 'base64') {
|
|
return AWS.util.base64.decode(member.textContent);
|
|
} else {
|
|
return member.textContent;
|
|
}
|
|
}
|
|
|
|
// return null for empty nodes of any other type
|
|
if (member.textContent === '') return null;
|
|
|
|
if (rules.type === 'integer') {
|
|
return parseInt(member.textContent, 10);
|
|
} else if (rules.type === 'float') {
|
|
return parseFloat(member.textContent);
|
|
} else if (rules.type === 'timestamp') {
|
|
return AWS.util.date.parseTimestamp(member.textContent);
|
|
} else if (rules.type === 'boolean') {
|
|
return member.textContent === 'true';
|
|
} else {
|
|
var msg = 'unhandled type: ' + rules.type;
|
|
throw AWS.util.error(new Error(msg), {code: 'XMLParserError'});
|
|
}
|
|
}
|
|
});
|