Express XML Body Parser Middleware
express-xml-bodyparser is a Connect/Express middleware designed to parse incoming raw XML request bodies, converting them into a JavaScript object available on `req.body`. It leverages the `xml2js` library for XML parsing. The current stable version is 0.4.1. The package has a slow release cadence, with updates typically addressing dependencies or minor fixes, rather than frequent feature additions. Key differentiators include its ability to parse data only once even if called multiple times, gracefully skip parsing for empty bodies, and accept a wide range of XML-based content-types (e.g., `application/rss+xml`). It provides custom configuration options that are merged with opinionated defaults to normalize the resulting JSON structure, such as trimming whitespace and lowercasing tag names, which users need to be aware of if they desire standard `xml2js` behavior. TypeScript type definitions are available via `@types/express-xml-bodyparser`.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'body')
cause The `req.body` property is `undefined` because the middleware did not parse the request body. This often happens if the `Content-Type` header is not an XML type, or the `express-xml-bodyparser` middleware is not applied before the route handler.fixEnsure the client sends `Content-Type: application/xml` (or another recognized XML MIME type like `application/rss+xml`). Verify that `app.use(xmlparser())` or `xmlparser()` is correctly placed before your route handler. -
UnhandledPromiseRejectionWarning: Error: Uncaught, unspecified 'error' event.
cause This error or similar uncaught exceptions can occur when processing malformed XML input, especially if the `async: true` option is enabled, which is discouraged.fixEnsure `async: false` is set (which is the default behavior in recent versions) or implement robust try-catch blocks around XML parsing if you explicitly require asynchronous processing and anticipate malformed input. -
XML body is not parsed as expected (e.g., tags not lowercased, arrays not explicit)
cause By default, `express-xml-bodyparser` merges your provided options with its own opinionated defaults, which include `normalize: true`, `normalizeTags: true`, `explicitArray: true`, and `trim: true`.fixTo override these opinionated defaults and use `xml2js`'s standard behavior, explicitly set the desired options to `false` in your configuration object, e.g., `xmlparser({ explicitArray: false, normalize: false, normalizeTags:
Warnings
- breaking Version 0.3.0 introduced a fix for a regression in handling custom MIME-type declarations. While a fix, it was noted as a 'potential breaking change for some applications' if they relied on the previous, incorrect behavior.
- deprecated Mutating the `xmlparser.regexp` property (e.g., `xmlparser.regexp = /your-regex/`) is deprecated as of v0.3.0 and will be removed entirely in v1.0.0. This practice can lead to nasty side-effects.
- gotcha Since v0.2.2, `async=false` is the default parsing mode due to upstream `node-xml2js` issues where malformed input could lead to uncaught exceptions in async mode. Using `async: true` is strongly discouraged unless you have robust input validation, as it can make your application vulnerable to crashes.
- breaking In v0.1.0, the options merging logic changed. Custom options are now *merged* with `express-xml-bodyparser`'s opinionated defaults (e.g., `explicitArray: true`, `normalize: true`, `normalizeTags: true`, `trim: true`), instead of being merged with `xml2js`'s raw defaults. Also, an empty request body now returns a 200 status instead of 411.
Install
-
npm install express-xml-bodyparser -
yarn add express-xml-bodyparser -
pnpm add express-xml-bodyparser
Imports
- xmlparser
const xmlparser = require('express-xml-bodyparser').default;import xmlparser from 'express-xml-bodyparser';
- xmlparser
const xmlparser = require('express-xml-bodyparser'); - MiddlewareFunction
import type { Request, Response, NextFunction } from 'express'; import type { Options as Xml2JsOptions } from 'xml2js';
Quickstart
import express from 'express';
import http from 'http';
import xmlparser from 'express-xml-bodyparser';
const app = express();
const server = http.createServer(app);
// Apply JSON and URL-encoded body parsers first if needed
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Apply the XML body parser globally
app.use(xmlparser());
app.post('/receive-xml', function(req, res, next) {
// req.body contains the parsed XML as a JavaScript object
console.log('Received XML body:', req.body);
if (req.body) {
res.status(200).json({ message: 'XML received', data: req.body });
} else {
res.status(400).json({ message: 'No XML body received' });
}
});
// Example of using xmlparser on a specific route with custom options
app.post('/receive-xml-custom', xmlparser({ trim: false, explicitArray: false }), function(req, res, next) {
console.log('Received custom XML body:', req.body);
if (req.body) {
res.status(200).json({ message: 'XML received with custom options', data: req.body });
} else {
res.status(400).json({ message: 'No XML body received' });
}
});
const PORT = 1337;
server.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`);
console.log('Send POST requests to /receive-xml or /receive-xml-custom with Content-Type: application/xml');
});