body-parser-xml, express-xml-bodyparser, and xml2js are npm packages used for handling XML data in Node.js applications, particularly when working with Express.js. xml2js is a general-purpose library that converts XML strings into JavaScript objects. In contrast, body-parser-xml and express-xml-bodyparser are Express middleware packages designed to automatically parse incoming XML request bodies and attach the resulting JavaScript object to req.body. However, both middleware packages rely on xml2js under the hood and differ primarily in their integration approach with Express.
When building APIs that consume XML payloads — common in legacy enterprise systems, SOAP services, or government integrations — you need a reliable way to parse incoming XML into JavaScript objects. The Node.js ecosystem offers several packages for this, but they serve different roles in the request-handling pipeline. Let’s clarify what each does and how they fit together.
It’s critical to understand that xml2js is not middleware — it’s a general-purpose XML-to-JS parser. In contrast, body-parser-xml and express-xml-bodyparser are Express middleware that use underlying parsers (often xml2js) to automatically parse request bodies.
xml2js: The Foundationxml2js converts raw XML strings into JavaScript objects. It doesn’t know anything about HTTP requests — you feed it a string, and it gives you an object.
// Using xml2js directly
const xml2js = require('xml2js');
const xmlString = `<user><name>Alice</name></user>`;
xml2js.parseString(xmlString, (err, result) => {
if (err) throw err;
console.log(result); // { user: { name: ['Alice'] } }
});
Note: By default, xml2js wraps text content in arrays. You can customize this with options like { explicitArray: false }.
body-parser-xml: Express Middleware Built on xml2jsThis package extends Express’s built-in body-parser to handle application/xml and text/xml content types. Under the hood, it uses xml2js.
// Using body-parser-xml
const express = require('express');
const bodyParserXML = require('body-parser-xml');
bodyParserXML(bodyParser); // monkey-patches body-parser
const app = express();
app.use(bodyParser.xml({
limit: '1MB',
xmlParseOptions: { explicitArray: false }
}));
app.post('/api/data', (req, res) => {
console.log(req.body); // already parsed JS object
res.sendStatus(200);
});
express-xml-bodyparser: Standalone XML MiddlewareThis is a self-contained Express middleware that also uses xml2js internally but doesn’t require patching body-parser.
// Using express-xml-bodyparser
const express = require('express');
const xmlBodyParser = require('express-xml-bodyparser');
const app = express();
app.use(xmlBodyParser({
limit: '1MB',
xmlOptions: { explicitArray: false }
}));
app.post('/api/data', (req, res) => {
console.log(req.body); // parsed JS object
res.sendStatus(200);
});
As of 2024:
body-parser-xml is deprecated. Its npm page states: "This package is no longer maintained. Please use alternatives." It hasn’t seen updates in years and relies on outdated dependencies.express-xml-bodyparser is also effectively unmaintained, with its last commit in 2018 and open issues about security vulnerabilities in its xml2js dependency.xml2js remains actively maintained, with recent releases addressing performance and security.🛑 Do not use
body-parser-xmlorexpress-xml-bodyparserin new projects. Their reliance on old versions ofxml2jsexposes you to known CVEs (e.g., ReDoS vulnerabilities). Instead, write your own lightweight middleware using the latestxml2js.
Because the middleware packages are outdated, they lock you into old, potentially vulnerable versions of xml2js. Rolling your own middleware gives you full control:
// Secure, modern XML middleware using latest xml2js
const xml2js = require('xml2js');
const getRawBody = require('raw-body');
function xmlMiddleware(options = {}) {
const parser = new xml2js.Parser({
explicitArray: false,
normalizeTags: true,
...options.xmlOptions
});
return async (req, res, next) => {
if (!/^(application|text)\/xml/i.test(req.headers['content-type'])) {
return next();
}
try {
const raw = await getRawBody(req, {
limit: options.limit || '1mb',
encoding: 'utf8'
});
req.body = await parser.parseStringPromise(raw);
next();
} catch (err) {
next(err);
}
};
}
// Usage
app.use(xmlMiddleware({ limit: '2mb', xmlOptions: { explicitArray: false } }));
This approach lets you:
xml2js with security patchesSometimes you don’t need middleware at all. Examples:
Parsing XML from a file:
const fs = require('fs');
const xml2js = require('xml2js');
const parser = new xml2js.Parser();
const xml = fs.readFileSync('data.xml', 'utf8');
const result = await parser.parseStringPromise(xml);
Consuming an XML API response in a service:
const axios = require('axios');
const xml2js = require('xml2js');
const { data } = await axios.get('https://api.example.com/data.xml');
const parser = new xml2js.Parser();
const jsObj = await parser.parseStringPromise(data);
In these cases, xml2js is the right and only tool you need.
If you’re maintaining a legacy app using express-xml-bodyparser, migrate like this:
Install latest xml2js and raw-body:
npm install xml2js raw-body
Replace the middleware with the custom one shown above.
Update parsing options to match your current behavior (e.g., explicitArray: false).
Add proper error handling for malformed XML.
| Package | Role | Maintenance Status | Recommendation |
|---|---|---|---|
body-parser-xml | Express middleware | ❌ Deprecated | Never use in new projects |
express-xml-bodyparser | Express middleware | ❌ Unmaintained | Avoid; migrate if possible |
xml2js | XML → JS parser library | ✅ Actively maintained | Use directly or in custom middleware |
xml2js and raw-body. It’s ~15 lines of code and gives you full control.xml2js directly.Remember: XML parsing is a solved problem, but the integration layer (middleware) is where most risks live. Keep it simple, keep it updated, and own your stack.
Avoid body-parser-xml entirely — it is officially deprecated and unmaintained, with known security vulnerabilities due to outdated dependencies. Do not use it in new projects, and migrate existing implementations to a custom solution using the latest xml2js.
Do not choose express-xml-bodyparser for new work. It has been unmaintained since 2018 and depends on vulnerable versions of xml2js. If you're stuck with it in a legacy system, replace it with a minimal custom middleware using up-to-date xml2js and raw-body.
Use xml2js when you need a reliable, actively maintained XML-to-JavaScript parser. It’s suitable for direct use in services, file processing, or as the foundation for custom Express middleware. Always pair it with proper error handling and security-conscious parsing options like explicitArray: false.
Adds XML parsing to the body-parser library, so you can convert incoming XML data into a JSON representation.
This is really useful if you want to deal with plain old JavaScript objects, but you need to interface with XML APIs.
npm install express body-parser body-parser-xml
This library adds an xml method to the body-parser object.
Initialise like so:
const bodyParser = require('body-parser');
require('body-parser-xml')(bodyParser);
Once initialised, you can use it just like any other body-parser middleware:
const app = require('express')();
app.use(bodyParser.xml());
This will parse any XML-based request and place it as a JavaScript object on req.body for your route handlers to use.
An XML-based request is determined by the value of the Content-Type header. By default, any Content-Type header ending in /xml or +xml will be parsed as XML. For example, the following Content-Types will all match:
text/xmlapplication/xmlapplication/rss+xmlIf you need to match against a custom Content-Type header, pass in the type to match as an option (see below).
You can also pass in options:
app.use(bodyParser.xml(options));
The options object accepts any of the following keys:
Specify the default character set for the text content if the charset is not specified in the Content-Type header of the request. Defaults to utf-8.
When set to true, then deflated (compressed) bodies will be inflated; when false, deflated bodies are rejected. Defaults to true.
Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the bytes library for parsing. Defaults to '100kb'.
The type option is used to determine what media type the middleware will parse. This option can be a string, array of strings, or a function. If not a function, type option is passed directly to the type-is library and this can be an extension name (like xml), a mime type (like application/xml), or a mime type with a wildcard (like / or _/xml). If a function, the type option is called as fn(req) and the request is parsed if it returns a truthy value. Defaults to ['_/xml', '+xml'].
The verify option, if supplied, is called as verify(req, res, buf, encoding), where buf is a Buffer of the raw request body and encoding is the encoding of the request. The parsing can be aborted by throwing an error.
This option controls the behaviour of the XML parser. You can pass any option that is supported by the xml2js library: see here for a list of these options.
const express = require('express');
const bodyParser = require('body-parser');
require('body-parser-xml')(bodyParser);
const app = express();
app.use(
bodyParser.xml({
limit: '1MB', // Reject payload bigger than 1 MB
xmlParseOptions: {
normalize: true, // Trim whitespace inside text nodes
normalizeTags: true, // Transform tags to lowercase
explicitArray: false, // Only put nodes in array if >1
},
}),
);
app.post('/users', function (req, res, body) {
// Any request with an XML payload will be parsed
// and a JavaScript object produced on req.body
// corresponding to the request payload.
console.log(req.body);
res.status(200).end();
});
This library was born out of a frustration that express-xml-bodyparser, the most popular XML-parsing library for express, doesn't support the regular body-parser options - in particular, limiting the payload size.
This library was written to use body-parser's text parser under the hood, and then passes the parsed string into the XML parser. We can therefore take advantage of body-parser's regular options, and support limiting the payload size, amongst other things.
MIT