parser.js
1 // Generated by CoffeeScript 1.12.7 2 (function() { 3 "use strict"; 4 var bom, defaults, events, isEmpty, processItem, processors, sax, setImmediate, 5 bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 6 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 7 hasProp = {}.hasOwnProperty; 8 9 sax = require('sax'); 10 11 events = require('events'); 12 13 bom = require('./bom'); 14 15 processors = require('./processors'); 16 17 setImmediate = require('timers').setImmediate; 18 19 defaults = require('./defaults').defaults; 20 21 isEmpty = function(thing) { 22 return typeof thing === "object" && (thing != null) && Object.keys(thing).length === 0; 23 }; 24 25 processItem = function(processors, item, key) { 26 var i, len, process; 27 for (i = 0, len = processors.length; i < len; i++) { 28 process = processors[i]; 29 item = process(item, key); 30 } 31 return item; 32 }; 33 34 exports.Parser = (function(superClass) { 35 extend(Parser, superClass); 36 37 function Parser(opts) { 38 this.parseString = bind(this.parseString, this); 39 this.reset = bind(this.reset, this); 40 this.assignOrPush = bind(this.assignOrPush, this); 41 this.processAsync = bind(this.processAsync, this); 42 var key, ref, value; 43 if (!(this instanceof exports.Parser)) { 44 return new exports.Parser(opts); 45 } 46 this.options = {}; 47 ref = defaults["0.2"]; 48 for (key in ref) { 49 if (!hasProp.call(ref, key)) continue; 50 value = ref[key]; 51 this.options[key] = value; 52 } 53 for (key in opts) { 54 if (!hasProp.call(opts, key)) continue; 55 value = opts[key]; 56 this.options[key] = value; 57 } 58 if (this.options.xmlns) { 59 this.options.xmlnskey = this.options.attrkey + "ns"; 60 } 61 if (this.options.normalizeTags) { 62 if (!this.options.tagNameProcessors) { 63 this.options.tagNameProcessors = []; 64 } 65 this.options.tagNameProcessors.unshift(processors.normalize); 66 } 67 this.reset(); 68 } 69 70 Parser.prototype.processAsync = function() { 71 var chunk, err; 72 try { 73 if (this.remaining.length <= this.options.chunkSize) { 74 chunk = this.remaining; 75 this.remaining = ''; 76 this.saxParser = this.saxParser.write(chunk); 77 return this.saxParser.close(); 78 } else { 79 chunk = this.remaining.substr(0, this.options.chunkSize); 80 this.remaining = this.remaining.substr(this.options.chunkSize, this.remaining.length); 81 this.saxParser = this.saxParser.write(chunk); 82 return setImmediate(this.processAsync); 83 } 84 } catch (error1) { 85 err = error1; 86 if (!this.saxParser.errThrown) { 87 this.saxParser.errThrown = true; 88 return this.emit(err); 89 } 90 } 91 }; 92 93 Parser.prototype.assignOrPush = function(obj, key, newValue) { 94 if (!(key in obj)) { 95 if (!this.options.explicitArray) { 96 return obj[key] = newValue; 97 } else { 98 return obj[key] = [newValue]; 99 } 100 } else { 101 if (!(obj[key] instanceof Array)) { 102 obj[key] = [obj[key]]; 103 } 104 return obj[key].push(newValue); 105 } 106 }; 107 108 Parser.prototype.reset = function() { 109 var attrkey, charkey, ontext, stack; 110 this.removeAllListeners(); 111 this.saxParser = sax.parser(this.options.strict, { 112 trim: false, 113 normalize: false, 114 xmlns: this.options.xmlns 115 }); 116 this.saxParser.errThrown = false; 117 this.saxParser.onerror = (function(_this) { 118 return function(error) { 119 _this.saxParser.resume(); 120 if (!_this.saxParser.errThrown) { 121 _this.saxParser.errThrown = true; 122 return _this.emit("error", error); 123 } 124 }; 125 })(this); 126 this.saxParser.onend = (function(_this) { 127 return function() { 128 if (!_this.saxParser.ended) { 129 _this.saxParser.ended = true; 130 return _this.emit("end", _this.resultObject); 131 } 132 }; 133 })(this); 134 this.saxParser.ended = false; 135 this.EXPLICIT_CHARKEY = this.options.explicitCharkey; 136 this.resultObject = null; 137 stack = []; 138 attrkey = this.options.attrkey; 139 charkey = this.options.charkey; 140 this.saxParser.onopentag = (function(_this) { 141 return function(node) { 142 var key, newValue, obj, processedKey, ref; 143 obj = {}; 144 obj[charkey] = ""; 145 if (!_this.options.ignoreAttrs) { 146 ref = node.attributes; 147 for (key in ref) { 148 if (!hasProp.call(ref, key)) continue; 149 if (!(attrkey in obj) && !_this.options.mergeAttrs) { 150 obj[attrkey] = {}; 151 } 152 newValue = _this.options.attrValueProcessors ? processItem(_this.options.attrValueProcessors, node.attributes[key], key) : node.attributes[key]; 153 processedKey = _this.options.attrNameProcessors ? processItem(_this.options.attrNameProcessors, key) : key; 154 if (_this.options.mergeAttrs) { 155 _this.assignOrPush(obj, processedKey, newValue); 156 } else { 157 obj[attrkey][processedKey] = newValue; 158 } 159 } 160 } 161 obj["#name"] = _this.options.tagNameProcessors ? processItem(_this.options.tagNameProcessors, node.name) : node.name; 162 if (_this.options.xmlns) { 163 obj[_this.options.xmlnskey] = { 164 uri: node.uri, 165 local: node.local 166 }; 167 } 168 return stack.push(obj); 169 }; 170 })(this); 171 this.saxParser.onclosetag = (function(_this) { 172 return function() { 173 var cdata, emptyStr, key, node, nodeName, obj, objClone, old, s, xpath; 174 obj = stack.pop(); 175 nodeName = obj["#name"]; 176 if (!_this.options.explicitChildren || !_this.options.preserveChildrenOrder) { 177 delete obj["#name"]; 178 } 179 if (obj.cdata === true) { 180 cdata = obj.cdata; 181 delete obj.cdata; 182 } 183 s = stack[stack.length - 1]; 184 if (obj[charkey].match(/^\s*$/) && !cdata) { 185 emptyStr = obj[charkey]; 186 delete obj[charkey]; 187 } else { 188 if (_this.options.trim) { 189 obj[charkey] = obj[charkey].trim(); 190 } 191 if (_this.options.normalize) { 192 obj[charkey] = obj[charkey].replace(/\s{2,}/g, " ").trim(); 193 } 194 obj[charkey] = _this.options.valueProcessors ? processItem(_this.options.valueProcessors, obj[charkey], nodeName) : obj[charkey]; 195 if (Object.keys(obj).length === 1 && charkey in obj && !_this.EXPLICIT_CHARKEY) { 196 obj = obj[charkey]; 197 } 198 } 199 if (isEmpty(obj)) { 200 obj = _this.options.emptyTag !== '' ? _this.options.emptyTag : emptyStr; 201 } 202 if (_this.options.validator != null) { 203 xpath = "/" + ((function() { 204 var i, len, results; 205 results = []; 206 for (i = 0, len = stack.length; i < len; i++) { 207 node = stack[i]; 208 results.push(node["#name"]); 209 } 210 return results; 211 })()).concat(nodeName).join("/"); 212 (function() { 213 var err; 214 try { 215 return obj = _this.options.validator(xpath, s && s[nodeName], obj); 216 } catch (error1) { 217 err = error1; 218 return _this.emit("error", err); 219 } 220 })(); 221 } 222 if (_this.options.explicitChildren && !_this.options.mergeAttrs && typeof obj === 'object') { 223 if (!_this.options.preserveChildrenOrder) { 224 node = {}; 225 if (_this.options.attrkey in obj) { 226 node[_this.options.attrkey] = obj[_this.options.attrkey]; 227 delete obj[_this.options.attrkey]; 228 } 229 if (!_this.options.charsAsChildren && _this.options.charkey in obj) { 230 node[_this.options.charkey] = obj[_this.options.charkey]; 231 delete obj[_this.options.charkey]; 232 } 233 if (Object.getOwnPropertyNames(obj).length > 0) { 234 node[_this.options.childkey] = obj; 235 } 236 obj = node; 237 } else if (s) { 238 s[_this.options.childkey] = s[_this.options.childkey] || []; 239 objClone = {}; 240 for (key in obj) { 241 if (!hasProp.call(obj, key)) continue; 242 objClone[key] = obj[key]; 243 } 244 s[_this.options.childkey].push(objClone); 245 delete obj["#name"]; 246 if (Object.keys(obj).length === 1 && charkey in obj && !_this.EXPLICIT_CHARKEY) { 247 obj = obj[charkey]; 248 } 249 } 250 } 251 if (stack.length > 0) { 252 return _this.assignOrPush(s, nodeName, obj); 253 } else { 254 if (_this.options.explicitRoot) { 255 old = obj; 256 obj = {}; 257 obj[nodeName] = old; 258 } 259 _this.resultObject = obj; 260 _this.saxParser.ended = true; 261 return _this.emit("end", _this.resultObject); 262 } 263 }; 264 })(this); 265 ontext = (function(_this) { 266 return function(text) { 267 var charChild, s; 268 s = stack[stack.length - 1]; 269 if (s) { 270 s[charkey] += text; 271 if (_this.options.explicitChildren && _this.options.preserveChildrenOrder && _this.options.charsAsChildren && (_this.options.includeWhiteChars || text.replace(/\\n/g, '').trim() !== '')) { 272 s[_this.options.childkey] = s[_this.options.childkey] || []; 273 charChild = { 274 '#name': '__text__' 275 }; 276 charChild[charkey] = text; 277 if (_this.options.normalize) { 278 charChild[charkey] = charChild[charkey].replace(/\s{2,}/g, " ").trim(); 279 } 280 s[_this.options.childkey].push(charChild); 281 } 282 return s; 283 } 284 }; 285 })(this); 286 this.saxParser.ontext = ontext; 287 return this.saxParser.oncdata = (function(_this) { 288 return function(text) { 289 var s; 290 s = ontext(text); 291 if (s) { 292 return s.cdata = true; 293 } 294 }; 295 })(this); 296 }; 297 298 Parser.prototype.parseString = function(str, cb) { 299 var err; 300 if ((cb != null) && typeof cb === "function") { 301 this.on("end", function(result) { 302 this.reset(); 303 return cb(null, result); 304 }); 305 this.on("error", function(err) { 306 this.reset(); 307 return cb(err); 308 }); 309 } 310 try { 311 str = str.toString(); 312 if (str.trim() === '') { 313 this.emit("end", null); 314 return true; 315 } 316 str = bom.stripBOM(str); 317 if (this.options.async) { 318 this.remaining = str; 319 setImmediate(this.processAsync); 320 return this.saxParser; 321 } 322 return this.saxParser.write(str).close(); 323 } catch (error1) { 324 err = error1; 325 if (!(this.saxParser.errThrown || this.saxParser.ended)) { 326 this.emit('error', err); 327 return this.saxParser.errThrown = true; 328 } else if (this.saxParser.ended) { 329 throw err; 330 } 331 } 332 }; 333 334 return Parser; 335 336 })(events.EventEmitter); 337 338 exports.parseString = function(str, a, b) { 339 var cb, options, parser; 340 if (b != null) { 341 if (typeof b === 'function') { 342 cb = b; 343 } 344 if (typeof a === 'object') { 345 options = a; 346 } 347 } else { 348 if (typeof a === 'function') { 349 cb = a; 350 } 351 options = {}; 352 } 353 parser = new exports.Parser(options); 354 return parser.parseString(str, cb); 355 }; 356 357 }).call(this);