git-off

git off handles large files in git repos
git clone https://noulin.net/git/git-off.git
Log | Files | Refs | README

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;