Command Line Tools¶
pygixml installs one entry point, pygixml, with five subcommands:
no Python code required for one-off queries, conversions, pretty-printing,
or filtering giant files from a shell pipeline. Every subcommand also
works spelled out as python -m pygixml <subcommand>, which is handy
when pygixml isn’t on your PATH (e.g. inside a virtualenv you
haven’t activated).
pygixml <subcommand> [OPTIONS] [ARGS]
python -m pygixml <subcommand> [OPTIONS] [ARGS]
Subcommand |
Loads |
Use it for |
|---|---|---|
|
full DOM |
pretty-print (and colorize) an XML file for the terminal: the
XML analog of |
|
full DOM |
ad-hoc XPath / dotted queries: a |
|
DOM or streamed |
converting a whole file to JSON, |
|
full DOM |
converting between XML, JSON, YAML, and TOON, any direction |
|
one record at a time |
filtering matches out of a file too big to load, bounded memory |
If you’re not sure which one you need: cat/query/convert
load the whole document, same as pygixml.parse_file() would:
fine for anything that comfortably fits in RAM. jsonify switches to
a constant-memory streamed conversion automatically once a file crosses
64MB (see Jsonify: XML to JSON). stream never loads more than one matched
element at a time, so it’s the only one of the five safe for a file
that’s genuinely too large to fit in memory: see Streaming: Constant-Memory Parsing for Big XML for
the underlying constant-memory parsing layer it’s built on.
pygixml cat¶
Pretty-print an XML file, with syntax coloring on a real terminal if
colorama is installed. This is
the XML analog of tools like bat or jq -C: you’re looking at a
file, not piping it into something else.
pygixml cat data.xml # pretty + colorized (auto: only
# on a real terminal, and only
# if colorama is installed)
cat data.xml | pygixml cat - # from stdin
pygixml cat data.xml --color always # force color even when piped
pygixml cat data.xml --color never # force plain, no color
pygixml cat data.xml --indent 4 # 4-space indent instead of 2
pygixml cat data.xml -o pretty.xml # write to a file instead of
# stdout (never colorized by
# 'auto' -- a file isn't a tty)
Flag |
Meaning |
|---|---|
|
XML file to display. |
|
Spaces per indent level. Default |
|
|
|
Write the result here instead of stdout. |
If colorama isn’t installed, cat still works exactly the same,
just without color: plain, pretty-printed XML, same as
--color never. Install it (along with YAML/TOON support for
convert) with pip install pygixml[all].
The XML declaration (<?xml version="1.0"?>) is preserved from the
source even though pugixml’s own serializer doesn’t round-trip it.
pygixml query¶
Query an XML file with either XPath or a lxml.objectify-style
dotted path: a jq/xq for XML you can fit in memory. See
DOM Parser and Objectify: Dotted Navigation for the underlying query languages.
# XPath (starts with / or //)
pygixml query data.xml "//user-profile[@id='101']/first_name"
# dotted, objectify-style (starts with .) -- first segment names the root
pygixml query data.xml ".database.user_profile.first_name"
pygixml query data.xml ".database.user_profile.@id" # attribute
pygixml query data.xml ".database.entry[1]" # index
pygixml query data.xml ".database.entry[*]" # all siblings
pygixml query data.xml ".database.user_profile.text()" # text content
# output formats
pygixml query data.xml ".database" --format xml
pygixml query data.xml ".database" --format json --pretty
# just the count, exit code like grep (0 = match, 1 = no match)
pygixml query data.xml ".database.entry[*]" --count
# multiple files, stdin, NUL-separated for xargs -0
pygixml query *.xml ".config.host"
cat data.xml | pygixml query - ".config.host"
pygixml query data.xml ".database.entry[*]" --null | xargs -0 -n1 echo
Flag |
Meaning |
|---|---|
|
One or more XML files (or |
|
How to render each match. Default |
|
Pretty-print |
|
Separator between multiple results. Default newline. |
|
|
|
Print only the number of matches. |
|
Suppress per-file error messages (still reflected in the exit code). |
Exit code is 0 if at least one match was found (across all files),
1 otherwise: the same convention as grep.
pygixml jsonify¶
Convert a whole XML file to JSON. json is a short alias for the
same subcommand.
pygixml jsonify data.xml # compact JSON to stdout
pygixml jsonify data.xml -p # pretty (2-space indent)
pygixml jsonify data.xml -o data.json # write to a file
pygixml jsonify data.xml --force-list item # always make <item> a list
cat data.xml | pygixml jsonify - # read from stdin
pygixml json data.xml # `json` is a short alias
Flag |
Meaning |
|---|---|
|
XML file to convert. |
|
Write JSON here instead of stdout. |
|
Pretty-print with a 2-space indent. |
|
Pretty-print with an N-space indent (implies |
|
Always serialize this child tag as a list, even with a single occurrence. Repeatable. |
|
Same meaning as |
|
Force streaming mode / force in-memory DOM mode, overriding the automatic size-based choice below. |
Automatically switches to stream_dump()
(constant memory: see Jsonify: XML to JSON for its complexity
characteristics) for files over 64MB; --stream/--no-stream
force one mode or the other regardless of size. Both modes produce
byte-identical output for the same input and options.
pygixml stream¶
Read a (possibly giant) file once, tag by tag, via
pygixml.iterparse(), and emit matching elements as JSON: never
holding more than one matched element’s subtree in memory at a time.
This is the tool for a file too large for pygixml query/jsonify’s
DOM mode.
# every <order>, one JSON object per line (JSONL)
pygixml stream orders.xml --tag order
# simple filters -- numeric or string, on a child path or an @attribute
pygixml stream orders.xml --tag order --where "total>100"
pygixml stream orders.xml --tag order --where "@status=shipped"
# multiple --where are AND'ed together
pygixml stream orders.xml --tag order \
--where "@status=shipped" --where "customer=acme"
# a real JSON array instead of JSONL -- still one pass, still bounded memory
pygixml stream orders.xml --tag order --where "total>100" --format array -p
# just count, or stop after N matches -- handy for sanity-checking a
# filter against the first few records of a multi-GB file
pygixml stream orders.xml --tag order --where "@status=shipped" --count
pygixml stream huge.xml --tag order --where "total>100" --limit 10
cat orders.xml | pygixml stream - --tag order
Flag |
Meaning |
|---|---|
|
XML file to scan. |
|
Required. Only elements with this tag are considered. |
|
Filter, e.g. |
|
|
|
Pretty-print each matched object. |
|
Same meaning as |
|
Stop after N matches; must be |
|
Print only the number of matches. |
|
Write output here instead of stdout. |
Exit code is 0 if at least one match was found, 1 otherwise
(--limit 0 matches nothing on purpose, so it exits 1 too).
pygixml convert¶
Convert a file between XML, JSON, YAML, and TOON, in any direction.
pygixml convert data.xml -o data.json # format guessed from extensions
pygixml convert data.xml -o data.yaml
pygixml convert data.json -o data.xml -p # pretty XML
pygixml convert data.yaml --to toon # stdout needs --to explicitly
cat data.xml | pygixml convert - --from xml --to json # stdin needs --from too
Flag |
Meaning |
|---|---|
|
File to convert. |
|
Write the result here instead of stdout (which requires |
|
Input format. Auto-detected from |
|
Output format. Auto-detected from |
|
Pretty-print, where the target format supports it (json, xml). |
|
Indent for json (a number of spaces) or xml (a literal string, e.g. a tab). |
Built on pygixml.formats.FormatDocument -- a small class
wrapping a plain dict (the same @attr/#text/list shape
pygixml.dictify.parse() produces), with to_json/to_xml/
to_yaml/to_toon methods and matching from_* classmethods,
importable directly for use in your own code:
from pygixml.formats import FormatDocument
doc = FormatDocument.from_xml(open("data.xml").read())
open("data.yaml", "w").write(doc.to_yaml())
open("data.toon", "w").write(doc.to_toon())
JSON and XML always work (stdlib json + this package’s own
dictify); YAML needs PyYAML
and TOON needs ctoon (also
written by the author of pygixml) -- both optional, and asking for a
format you don’t have the package for gives a clear
pip install ... error instead of a crash:
pip install pygixml[all] # colorama (for `cat`) + PyYAML + ctoon
Like cat/query, this loads the whole document -- for XML too
big to fit in memory, convert with pygixml jsonify --stream or
pygixml stream instead.
Exit codes¶
Code |
Meaning |
|---|---|
|
Success (for |
|
No match ( |
|
Argument error (bad flag, bad |
|
A required optional dependency is missing ( |