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);