Skip to content

Commit 65f3aba

Browse files
committed
Initial Commit
0 parents  commit 65f3aba

File tree

4 files changed

+203
-0
lines changed

4 files changed

+203
-0
lines changed

.gitignore

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
# Created by https://www.gitignore.io/api/node
3+
4+
### Node ###
5+
# Logs
6+
logs
7+
*.log
8+
npm-debug.log*
9+
10+
# Runtime data
11+
pids
12+
*.pid
13+
*.seed
14+
15+
# Directory for instrumented libs generated by jscoverage/JSCover
16+
lib-cov
17+
18+
# Coverage directory used by tools like istanbul
19+
coverage
20+
21+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
22+
.grunt
23+
24+
# node-waf configuration
25+
.lock-wscript
26+
27+
# Compiled binary addons (http://nodejs.org/api/addons.html)
28+
build/Release
29+
30+
# Dependency directory
31+
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
32+
node_modules
33+
34+
# Optional npm cache directory
35+
.npm
36+
37+
# Optional REPL history
38+
.node_repl_history
39+

index.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
var xml2js = require('xml2js'),
4+
typeis = require('type-is');
5+
6+
module.exports = function(bodyParser) {
7+
if(bodyParser.xml) {
8+
// We already setup the XML parser.
9+
// End early.
10+
return;
11+
}
12+
13+
var xmlTypes = ['application/xml', 'text/xml'];
14+
15+
function xml(options) {
16+
options = options || {};
17+
options.type = xmlTypes;
18+
19+
var textParser = bodyParser.text(options);
20+
return function xmlParser(req, res, next) {
21+
// First, run the body through the text parser.
22+
textParser(req, res, function(err) {
23+
if(err) { return next(err); }
24+
if(!typeis(req, xmlTypes)) { return next(); }
25+
26+
// Then, parse as XML.
27+
var parser = new xml2js.Parser(options.xmlParseOptions);
28+
parser.parseString(req.body, function(err, xml) {
29+
if(err) {
30+
err.status = 400;
31+
return next(err);
32+
}
33+
34+
req.body = xml || req.body;
35+
next();
36+
});
37+
});
38+
};
39+
}
40+
41+
// Finally add the `xml` function to the bodyParser.
42+
Object.defineProperty(bodyParser, 'xml', {
43+
configurable: true,
44+
enumerable: true,
45+
get: function() {
46+
return xml;
47+
}
48+
});
49+
};

package.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "body-parser-xml",
3+
"version": "1.0.0-alpha1",
4+
"description": "Adds an XML parser to body-parser.",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "node_modules/mocha/bin/mocha test.js"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/fiznool/body-parser-xml.git"
12+
},
13+
"keywords": [
14+
"express",
15+
"xml",
16+
"body-parser"
17+
],
18+
"author": "Tom Spencer <[email protected]>",
19+
"license": "MIT",
20+
"bugs": {
21+
"url": "https://github.com/fiznool/body-parser-xml/issues"
22+
},
23+
"homepage": "https://github.com/fiznool/body-parser-xml#readme",
24+
"dependencies": {
25+
"type-is": "^1.6.10",
26+
"xml2js": "^0.4.15"
27+
},
28+
"devDependencies": {
29+
"body-parser": "^1.14.2",
30+
"chai": "^3.4.1",
31+
"express": "^4.13.3",
32+
"mocha": "^2.3.4",
33+
"supertest": "^1.1.0"
34+
}
35+
}

test.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
'use strict';
2+
3+
var express = require('express'),
4+
request = require('supertest'),
5+
bodyParser = require('body-parser'),
6+
expect = require('chai').expect;
7+
8+
// Add xml parsing to bodyParser.
9+
// In real-life you'd `require('body-parser-xml')`.
10+
require('./index.js')(bodyParser);
11+
12+
describe('XML Body Parser', function() {
13+
var app;
14+
15+
var createServer = function(options) {
16+
app = express();
17+
app.use(bodyParser.xml(options));
18+
app.post('/', function(req, res) {
19+
res.status(200).send({ parsed: req.body });
20+
});
21+
};
22+
23+
beforeEach(function() {
24+
app = null;
25+
});
26+
27+
it('should parse a body with content-type application/xml', function(done) {
28+
createServer();
29+
30+
request(app)
31+
.post('/')
32+
.set('Content-Type', 'application/xml')
33+
.send('<customer><name>Bob</name></customer>')
34+
.expect(200, { parsed: { customer: { name: ['Bob'] } } }, done);
35+
});
36+
37+
it('should parse a body with content-type text/xml', function(done) {
38+
createServer();
39+
40+
request(app)
41+
.post('/')
42+
.set('Content-Type', 'text/xml')
43+
.send('<customer><name>Bob</name></customer>')
44+
.expect(200, { parsed: { customer: { name: ['Bob'] } } }, done);
45+
});
46+
47+
it('should accept xmlParseOptions', function(done) {
48+
createServer({
49+
xmlParseOptions: {
50+
normalize: true, // Trim whitespace inside text nodes
51+
normalizeTags: true, // Transform tags to lowercase
52+
explicitArray: false // Only put nodes in array if >1
53+
}
54+
});
55+
request(app)
56+
.post('/')
57+
.set('Content-Type', 'text/xml')
58+
.send('<CUSTOMER><name> Bob </name></CUSTOMER>')
59+
.expect(200, { parsed: { customer: { name: 'Bob' } } }, done);
60+
});
61+
62+
it('should ignore non-XML', function(done) {
63+
createServer();
64+
65+
request(app)
66+
.post('/')
67+
.set('Content-Type', 'text/plain')
68+
.send('Customer name: Bob')
69+
.expect(200, { parsed: {} }, done);
70+
});
71+
72+
it('should reject invalid XML', function(done) {
73+
createServer();
74+
request(app)
75+
.post('/')
76+
.set('Content-Type', 'text/xml')
77+
.send('<invalid-xml>')
78+
.expect(400, done);
79+
});
80+
});

0 commit comments

Comments
 (0)