parsers.js
2.52 KB
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;