xml2pdf Playground Source

Command line

The xml2pdf binary renders one XML file to one PDF. It's a single static executable with no runtime dependencies.

Install

Install script (Linux & macOS)

curl -fsSL https://raw.githubusercontent.com/sandeepkumarmishra354/xml-to-pdf/main/install.sh | sh

The script works out your OS and CPU, downloads the matching archive from the latest release, verifies its SHA-256 checksum against checksums.txt, and installs xml2pdf to /usr/local/bin. If that directory isn't writable, it uses sudo or falls back to ~/.local/bin. It needs curl or wget.

VariableDescription
XML2PDF_VERSIONVersion to install, e.g. 0.1.0. The default is the latest release.
XML2PDF_INSTALL_DIRDirectory to install into, e.g. ~/bin.
curl -fsSL https://raw.githubusercontent.com/sandeepkumarmishra354/xml-to-pdf/main/install.sh | XML2PDF_VERSION=0.1.0 XML2PDF_INSTALL_DIR="$HOME/bin" sh

Binaries installed this way aren't blocked by macOS Gatekeeper, because only files downloaded through a web browser are flagged.

Download a binary

Prebuilt binaries for Linux, macOS and Windows (amd64 and arm64) are attached to every GitHub release. Download the archive for your platform, unpack it, and put xml2pdf somewhere on your PATH:

# Example: Linux, x86-64 (replace VERSION with the release number, e.g. 0.1.0)
curl -LO https://github.com/sandeepkumarmishra354/xml-to-pdf/releases/download/vVERSION/xml2pdf_VERSION_linux_amd64.tar.gz
tar xzf xml2pdf_VERSION_linux_amd64.tar.gz
sudo mv xml2pdf /usr/local/bin/
xml2pdf --version

Each archive also contains the README, the license and the example documents. checksums.txt in the release lists the SHA-256 of every archive.

macOS: the binaries aren't notarized, so a binary downloaded through a browser shows "Apple could not verify xml2pdf…" the first time it runs. Use the install script instead, or clear the flag with xattr -d com.apple.quarantine xml2pdf, or allow it under System Settings → Privacy & Security.

With Go

go install github.com/sandeepkumarmishra354/xml-to-pdf/cmd/xml2pdf@latest

This installs xml2pdf into $(go env GOPATH)/bin. It needs Go 1.24 or newer.

From source

git clone https://github.com/sandeepkumarmishra354/xml-to-pdf
cd xml-to-pdf
make build          # static binary at bin/xml2pdf

Cross-compiling

The renderer is pure Go (no cgo), so you can build binaries for every platform from any machine:

make dist
# dist/xml2pdf-linux-amd64        dist/xml2pdf-linux-arm64
# dist/xml2pdf-darwin-amd64       dist/xml2pdf-darwin-arm64
# dist/xml2pdf-windows-amd64.exe  dist/xml2pdf-windows-arm64.exe

Copy the binary for your platform anywhere on your PATH; nothing else is needed.

Usage

xml2pdf [flags] input.xml

Flags may come before or after the input file. Both -flag and --flag forms work.

FlagDescription
-o FILEOutput PDF path. The default is the input path with a .pdf extension (report.xml → report.pdf). Use - to write to standard output.
--data FILEA JSON file whose top level is an object. Its values are available as ${key}, ${a.b} or ${list.0.c}, and its arrays can be looped over with <for-each>.
--json JSONThe same as --data, but takes the JSON object inline: --json '{"name":"Alice"}'. See Passing data.
--set KEY=VALUESets a variable. Repeat it for several. It overrides --data, --json and document constants.
--base-dir DIRDirectory that relative image paths resolve against. The default is the input file's directory, or the working directory when reading from stdin.
--versionPrints the version and exits.
-h, --helpShows the help.

Use - as the input file to read XML from standard input.

Examples

# Render, writing report.pdf next to report.xml
xml2pdf report.xml

# Choose the output path
xml2pdf report.xml -o out/report-2026.pdf

# Fill a template from JSON
xml2pdf invoice.xml --data customers/globex.json -o globex.pdf

# Inline JSON, no file needed
xml2pdf invoice.xml --json '{"invoice_no":"42","items":[{"name":"Hosting","qty":1}]}'

# JSON piped from another program
curl -s https://api.example.com/invoices/42 | xml2pdf invoice.xml --data - -o 42.pdf

# Override individual values (handy in scripts)
xml2pdf invoice.xml --data globex.json --set status=PAID --set due_date=2026-12-01

# Pipes: read XML from stdin, write the PDF to stdout
generate-xml | xml2pdf - --base-dir ./assets -o - > out.pdf

# Batch rendering
for f in data/*.json; do
  xml2pdf template.xml --data "$f" -o "out/$(basename "$f" .json).pdf"
done

Passing data

Templates get their values from JSON. There are three ways to supply it, and you can combine them:

SourceExample
A file--data invoice.json
Inline--json '{"customer":{"name":"Globex"}}'
Standard inputsome-api | xml2pdf invoice.xml --data -

The top level must be a JSON object. --data and --json can be repeated and mixed, and they're deep-merged from left to right: nested objects combine key by key, and any other value (string, number, boolean, array or null) is replaced by the later one.

# Start from a file and override a nested field and a top-level value
xml2pdf invoice.xml --data invoice.json --json '{"customer":{"name":"Initech"},"status":"PAID"}'
# customer.address still comes from invoice.json

# Shared defaults plus per-customer data
xml2pdf invoice.xml --data defaults.json --data customers/globex.json

Finally, --set key=value overrides any single value, whatever its source. The full lookup order is described under Variables.

Quoting: wrap inline JSON in single quotes in bash and zsh, so the shell leaves the double quotes alone. PowerShell 7.3 and newer also accept single quotes. Older Windows PowerShell and cmd.exe mangle the inner quotes; there, escape them (--json "{\"name\":\"Alice\"}"), or use a file or stdin instead. Standard input can be used only once, so --data - can't be combined with reading the XML from stdin.

Exit status and errors

xml2pdf exits with 0 on success. On any error it prints a message to standard error, exits with 1, and doesn't write the output file. Messages include the file and line:

$ xml2pdf invoice.xml
xml2pdf: invoice.xml: line 41: undefined variable "customer.nmae"

Makefile targets

TargetDescription
make buildBuilds a static bin/xml2pdf with the version from git describe.
make testRuns the test suite.
make vetChecks formatting (gofmt) and runs go vet.
make examplesRenders examples/*.xml into bin/.
make distCross-compiles release binaries into dist/.
make docsRebuilds this documentation site in docs/.
make snapshotBuilds release archives locally with GoReleaser, without publishing.
make cleanRemoves bin/ and dist/.

Releasing

Releases are automated with GoReleaser and GitHub Actions. Pushing a tag that starts with v runs the tests, builds every platform, and publishes a GitHub Release with archives, checksums and a changelog:

git tag v0.1.0
git push origin v0.1.0

Tags with a pre-release suffix, such as v0.2.0-rc.1, are marked as pre-releases automatically.