How to Convert XML to PDF with JavaScript in NodeJS

Use JavaScript in NodeJS to turn XML files into styled, tagged PDFs with configurable hierarchy and source views.
Share this page

This walkthrough uses JavaScript in NodeJS to convert an XML file with the pdfRest Convert to PDF API Tool. It sends the source and structured-text settings in one multipart request, producing a tagged PDF with a readable nested layout.

Why Convert XML to PDF with JavaScript in NodeJS?

Modern NodeJS services still encounter XML through payment gateways, legacy APIs, syndication feeds, and business-to-business integrations. Returning that raw payload to a user or account team creates unnecessary friction because the structure is difficult to scan and the file may open differently across tools.

Imagine a SaaS support portal that retrieves an XML status response from an older provisioning system. When an escalation is opened, the backend can create a PDF snapshot and add it to the case. Hierarchy presentation makes nested account, service, and error values understandable to the support engineer, while PDF provides a familiar artifact that can be downloaded or forwarded.

NodeJS applications can also request source presentation when troubleshooting requires the exact tags and nesting to remain visible. Because both views use the same /pdf endpoint, the application can choose the presentation that matches the audience instead of maintaining separate rendering pipelines.

JavaScript Code Example for Converting XML to PDF

var axios = require("axios");
var fs = require("fs");
var FormData = require("form-data");

// By default, we use the US-based API service. This is the primary endpoint for global use.
var apiUrl = "https://api.pdfrest.com";

/* For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below.
 * For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
 */
//var apiUrl = "https://eu-api.pdfrest.com";

// This sample converts XML input to a tagged PDF through multipart /pdf.
// It demonstrates structured_text_options and the format-specific conversion options.
var inputPath = "/path/to/sample.xml";
var form = new FormData();
form.append("file", fs.createReadStream(inputPath));
form.append("structured_text_options", JSON.stringify({"title":"Structured Content Sample","language":"en-US","enable_tagging":true,"page_setup":{"size":"Letter","orientation":"portrait","margin":{"top":36,"right":42,"bottom":36,"left":42}},"style":{"font":"Arial","heading_font":"Arial","code_font":"Courier","text_size":11,"text_color_rgb":[34,34,34],"heading_scale":1.35,"table":{"column_width_weights":[2,3,2],"keep_header_with_first_row":true,"repeat_headers_on_overflow":true,"show_borders":true,"border_width":0.75,"border_color_rgb":[180,188,200],"header_fill_color_rgb":[33,64,98],"header_text_color_rgb":[255,255,255],"row_fill_color_rgb":[250,250,252],"alternate_row_fill_color_rgb":[235,240,246],"cell_padding":{"top":6,"right":8,"bottom":6,"left":8}}},"data_presentation":"hierarchy"}));
form.append("output", "pdf_from_xml");

axios.post(apiUrl + "/pdf", form, { headers: { "Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", ...form.getHeaders() }, maxBodyLength: Infinity })
.then((response) => { console.log(JSON.stringify(response.data, null, 2)); })
.catch((error) => { console.error(error.response ? error.response.data : error.message); process.exitCode = 1; });

Source: View the sample on GitHub

Breaking Down the Code

The NodeJS XML walkthrough uses axios, form-data, and Node’s file-system module. Outside the samples project, install its HTTP and multipart dependencies with npm install axios form-data.

var axios = require("axios");
var fs = require("fs");
var FormData = require("form-data");

This NodeJS excerpt keeps the regional endpoint visible for the XML workflow:

// By default, we use the US-based API service. This is the primary endpoint for global use.
var apiUrl = "https://api.pdfrest.com";

/* For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below.
 * For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
 */
//var apiUrl = "https://eu-api.pdfrest.com";

JavaScript streams the .xml source into the form while preserving its filename. pdfRest infers XML conversion from that extension, so structured_text_options does not need an input_format property.

// It demonstrates structured_text_options and the format-specific conversion options.
var inputPath = "/path/to/sample.xml";
var form = new FormData();

The object passed through JSON.stringify is interpreted by pdfRest as structured_text_options. It sets PDF metadata, explicitly enables tagging, defines Letter portrait geometry and margins, and supplies the font and color choices used when laying out the XML content.

{
  "data_presentation": "hierarchy"
}

source is the default. It first validates the XML and then displays the user’s original source text, including its markup, whitespace, and declared encoding text. hierarchy instead creates a nested list: local element names become bold labels, attributes appear with an @ prefix, and leaf values follow their element names. Namespace prefixes are not displayed in hierarchy labels. Invalid XML and documents without a root element are rejected in either mode.

The shared style.table member does not affect XML hierarchy or source output. It can be removed from an XML-only profile without changing the resulting document.

NodeJS uses FormData to append the XML file, stringified structured_text_options, and output name. The generated form headers provide the multipart boundary for those fields.

var inputPath = "/path/to/sample.xml";
var form = new FormData();
form.append("file", fs.createReadStream(inputPath));
form.append("structured_text_options", JSON.stringify({"title":"Structured Content Sample","language":"en-US","enable_tagging":true,"page_setup":{"size":"Letter","orientation":"portrait","margin":{"top":36,"right":42,"bottom":36,"left":42}},"style":{"font":"Arial","heading_font":"Arial","code_font":"Courier","text_size":11,"text_color_rgb":[34,34,34],"heading_scale":1.35,"table":{"column_width_weights":[2,3,2],"keep_header_with_first_row":true,"repeat_headers_on_overflow":true,"show_borders":true,"border_width":0.75,"border_color_rgb":[180,188,200],"header_fill_color_rgb":[33,64,98],"header_text_color_rgb":[255,255,255],"row_fill_color_rgb":[250,250,252],"alternate_row_fill_color_rgb":[235,240,246],"cell_padding":{"top":6,"right":8,"bottom":6,"left":8}}},"data_presentation":"hierarchy"}));
form.append("output", "pdf_from_xml");

axios.post(apiUrl + "/pdf", form, { headers: { "Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", ...form.getHeaders() }, maxBodyLength: Infinity })
.then((response) => { console.log(JSON.stringify(response.data, null, 2)); })
.catch((error) => { console.error(error.response ? error.response.data : error.message); process.exitCode = 1; });

Axios sends the XML request to /pdf with the form headers and Api-Key. Its success path prints resource JSON, while the rejection path exposes either the API response or the client-side error.

form.append("file", fs.createReadStream(inputPath));
form.append("structured_text_options", JSON.stringify({"title":"Structured Content Sample","language":"en-US","enable_tagging":true,"page_setup":{"size":"Letter","orientation":"portrait","margin":{"top":36,"right":42,"bottom":36,"left":42}},"style":{"font":"Arial","heading_font":"Arial","code_font":"Courier","text_size":11,"text_color_rgb":[34,34,34],"heading_scale":1.35,"table":{"column_width_weights":[2,3,2],"keep_header_with_first_row":true,"repeat_headers_on_overflow":true,"show_borders":true,"border_width":0.75,"border_color_rgb":[180,188,200],"header_fill_color_rgb":[33,64,98],"header_text_color_rgb":[255,255,255],"row_fill_color_rgb":[250,250,252],"alternate_row_fill_color_rgb":[235,240,246],"cell_padding":{"top":6,"right":8,"bottom":6,"left":8}}},"data_presentation":"hierarchy"}));
form.append("output", "pdf_from_xml");

axios.post(apiUrl + "/pdf", form, { headers: { "Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", ...form.getHeaders() }, maxBodyLength: Infinity })
.then((response) => { console.log(JSON.stringify(response.data, null, 2)); })
.catch((error) => { console.error(error.response ? error.response.data : error.message); process.exitCode = 1; });

Beyond the Tutorial

This approach can turn XML-based monitoring output, inventory feeds, or integration test results into documents that product and operations teams can inspect comfortably. Developers still retain source mode for cases where exact syntax is central to the review.

Logical tagging can improve navigation and machine interpretation, but the sample makes no claim of complete accessibility conformance. Use API Lab to explore the profile and review all accepted fields in the Convert to PDF documentation.

Generate a self-service API Key now!
Create your FREE API Key to start processing PDFs in seconds, only possible with pdfRest.