Blame view

node_modules/needle/lib/parsers.js 2.56 KB
7820380e   “wangming”   1
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
121
  //////////////////////////////////////////
  // 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.oncdata = 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',
    'application/vnd.api+json'
  ], 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;