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.
| Variable | Description |
|---|---|
XML2PDF_VERSION | Version to install, e.g. 0.1.0. The default is the latest release. |
XML2PDF_INSTALL_DIR | Directory 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.
| Flag | Description |
|---|---|
-o FILE | Output PDF path. The default is the input path with a .pdf extension (report.xml → report.pdf). Use - to write to standard output. |
--data FILE | A 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 JSON | The same as --data, but takes the JSON object inline: --json '{"name":"Alice"}'. See Passing data. |
--set KEY=VALUE | Sets a variable. Repeat it for several. It overrides --data, --json and document constants. |
--base-dir DIR | Directory that relative image paths resolve against. The default is the input file's directory, or the working directory when reading from stdin. |
--version | Prints the version and exits. |
-h, --help | Shows 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:
| Source | Example |
|---|---|
| A file | --data invoice.json |
| Inline | --json '{"customer":{"name":"Globex"}}' |
| Standard input | some-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
| Target | Description |
|---|---|
make build | Builds a static bin/xml2pdf with the version from git describe. |
make test | Runs the test suite. |
make vet | Checks formatting (gofmt) and runs go vet. |
make examples | Renders examples/*.xml into bin/. |
make dist | Cross-compiles release binaries into dist/. |
make docs | Rebuilds this documentation site in docs/. |
make snapshot | Builds release archives locally with GoReleaser, without publishing. |
make clean | Removes 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.