summaryrefslogtreecommitdiff
path: root/node_modules/needle/lib/parsers.js
blob: 108b17bb4fe18d3514cdd9bf85c3965393b482cb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//////////////////////////////////////////
// Defines mappings between content-type
// and the appropriate parsers.
//////////////////////////////////////////

var Transform = require('stream').Transform;
var sax = require('sax');

function parseXML(str, cb) {
  var obj, current, parser = sax.parser(true, { trim: true, lowercase: true })
  parser.onerror = parser.onend = done;

  function done(err) {
    parser.onerror = parser.onend = function() { }
    cb(err, obj)
  }

  function newElement(name, attributes) {
    return {
      name: name || '',
      value: '',
      attributes: attributes || {},
      children: []
    }
  }

  parser.ontext = function(t) {
    if (current) current.value += t
  }

  parser.onopentag = function(node) {
    var element = newElement(node.name, node.attributes)
    if (current) {
      element.parent = current
      current.children.push(element)
    } else { // root object
      obj = element
    }

    current = element
  };

  parser.onclosetag = function() {
    if (typeof current.parent !== 'undefined') {
      var just_closed = current
      current = current.parent
      delete just_closed.parent
    }
  }

  parser.write(str).close()
}

function parserFactory(name, fn) {

  function parser() {
    var chunks = [],
        stream = new Transform({ objectMode: true });

    // Buffer all our data
    stream._transform = function(chunk, encoding, done) {
      chunks.push(chunk);
      done();
    }

    // And call the parser when all is there.
    stream._flush = function(done) {
      var self = this,
          data = Buffer.concat(chunks);

      try {
        fn(data, function(err, result) {
          if (err) throw err;
          self.push(result);
        });
      } catch (err) {
        self.push(data); // just pass the original data
      } finally {
        done();
      }
    }

    return stream;
  }

  return { fn: parser, name: name };
}

var parsers = {}

function buildParser(name, types, fn) {
  var parser = parserFactory(name, fn);
  types.forEach(function(type) {
    parsers[type] = parser;
  })
}

buildParser('json', [
  'application/json',
  'text/javascript'
], function(buffer, cb) {
  var err, data;
  try { data = JSON.parse(buffer); } catch (e) { err = e; }
  cb(err, data);
});

buildParser('xml', [
  'text/xml',
  'application/xml',
  'application/rdf+xml',
  'application/rss+xml',
  'application/atom+xml'
], function(buffer, cb) {
  parseXML(buffer.toString(), function(err, obj) {
    cb(err, obj)
  })
});

module.exports = parsers;
module.exports.use = buildParser;