parsers.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. //////////////////////////////////////////
  2. // Defines mappings between content-type
  3. // and the appropriate parsers.
  4. //////////////////////////////////////////
  5. var Transform = require('stream').Transform;
  6. var sax = require('sax');
  7. function parseXML(str, cb) {
  8. var obj, current, parser = sax.parser(true, { trim: true, lowercase: true })
  9. parser.onerror = parser.onend = done;
  10. function done(err) {
  11. parser.onerror = parser.onend = function() { }
  12. cb(err, obj)
  13. }
  14. function newElement(name, attributes) {
  15. return {
  16. name: name || '',
  17. value: '',
  18. attributes: attributes || {},
  19. children: []
  20. }
  21. }
  22. parser.oncdata = parser.ontext = function(t) {
  23. if (current) current.value += t
  24. }
  25. parser.onopentag = function(node) {
  26. var element = newElement(node.name, node.attributes)
  27. if (current) {
  28. element.parent = current
  29. current.children.push(element)
  30. } else { // root object
  31. obj = element
  32. }
  33. current = element
  34. };
  35. parser.onclosetag = function() {
  36. if (typeof current.parent !== 'undefined') {
  37. var just_closed = current
  38. current = current.parent
  39. delete just_closed.parent
  40. }
  41. }
  42. parser.write(str).close()
  43. }
  44. function parserFactory(name, fn) {
  45. function parser() {
  46. var chunks = [],
  47. stream = new Transform({ objectMode: true });
  48. // Buffer all our data
  49. stream._transform = function(chunk, encoding, done) {
  50. chunks.push(chunk);
  51. done();
  52. }
  53. // And call the parser when all is there.
  54. stream._flush = function(done) {
  55. var self = this,
  56. data = Buffer.concat(chunks);
  57. try {
  58. fn(data, function(err, result) {
  59. if (err) throw err;
  60. self.push(result);
  61. });
  62. } catch (err) {
  63. self.push(data); // just pass the original data
  64. } finally {
  65. done();
  66. }
  67. }
  68. return stream;
  69. }
  70. return { fn: parser, name: name };
  71. }
  72. var parsers = {}
  73. function buildParser(name, types, fn) {
  74. var parser = parserFactory(name, fn);
  75. types.forEach(function(type) {
  76. parsers[type] = parser;
  77. })
  78. }
  79. buildParser('json', [
  80. 'application/json',
  81. 'application/hal+json',
  82. 'text/javascript',
  83. 'application/vnd.api+json'
  84. ], function(buffer, cb) {
  85. var err, data;
  86. try { data = JSON.parse(buffer); } catch (e) { err = e; }
  87. cb(err, data);
  88. });
  89. buildParser('xml', [
  90. 'text/xml',
  91. 'application/xml',
  92. 'application/rdf+xml',
  93. 'application/rss+xml',
  94. 'application/atom+xml'
  95. ], function(buffer, cb) {
  96. parseXML(buffer.toString(), function(err, obj) {
  97. cb(err, obj)
  98. })
  99. });
  100. module.exports = parsers;
  101. module.exports.use = buildParser;