Skip to main content

pygxml

streaming parser using gjson-style path queries over XML. Rust core (quick-xml) + PyO3.

The original GJSON: tidwall/gjson

Installation

pip install pygxml

Usage examples

import pygxml

xml = """<store>
  <book id="b1"><title>XML in a Nutshell</title><price>30</price></book>
  <book id="b2"><title>The Cathedral and the Bazaar</title><price>20</price></book>
  <book id="b3"><title>Programming Rust</title><price>45</price></book>
</store>"""

# Single-shot path query — returns a typed Result.
pygxml.get(xml, "store.book").type_                         # list (3 books)
pygxml.get(xml, "store.book.0.title").to_str()             # 'XML in a Nutshell'
pygxml.get(xml, "store.book.1.@id").to_str()               # 'b2'
pygxml.get(xml, "store.book.#").to_int()                   # 3
[str(r) for r in pygxml.get(xml, "store.book.#.title")]    # ['XML in a Nutshell', ...]

# A bare child name with multiple matches AND a follow-on step is rejected:
# the user must pick `.N` (single) or `.#` (each).
pygxml.get(xml, "store.book.title")                         # ValueError

# Filters
pygxml.get(xml, "store.book.#(price>=30).title").to_str()           # 'XML in a Nutshell'
[str(r) for r in pygxml.get(xml, "store.book.#(price>=30)#.title")] # all matches
pygxml.get(xml, 'store.book.#(@id=="b2").title').to_str()           # 'The Cathedral...'

# Modifiers
pygxml.get(xml, "store.book.#.title|@count").to_int()               # 3

# Result.get(...) — descend into a captured element fragment.
book = pygxml.get(xml, "store.book.0")
book.get("title").to_str()                                # 'XML in a Nutshell'
book.get("@id").to_str()                                  # 'b1'
book.get("price").to_int()                                # 30

# Result.children() — walk direct child elements in document order,
# keeping duplicate tag names.
store = pygxml.get(xml, "store")
[name for name, _ in store.children()]                    # ['book', 'book', 'book']
[c.get("title").to_str() for _, c in store.children()]    # ['XML in a Nutshell', ...]

# parse(data) — wrap the input as a top-level Result for chained navigation.
r = pygxml.parse(xml)
r.get("store.book.0.title").to_str()                      # 'XML in a Nutshell'
r.get("store.book.#(price>=30)#.title").value             # [Result('XML in a Nutshell'), Result('Programming Rust')]

# get_many — scan the document once and return multiple Results.
title, price = pygxml.get_many(xml, ["store.book.0.title", "store.book.0.price"])

# compile() — pre-compile a path for reuse across many documents.
path = pygxml.compile("store.book.0.title")
path.get(xml).to_str()                                    # 'XML in a Nutshell'

# Compiled paths can also be passed to get_many / get_many_bytes / get_many_buffer.
title_path = pygxml.compile("store.book.0.title")
price_path = pygxml.compile("store.book.0.price")
title, price = pygxml.get_many(xml, [title_path, price_path])

# mmap input — true zero-copy on huge files. parse(mm) keeps the mmap by
# reference, so subsequent .get() calls re-borrow it without copying.
import mmap
with open('huge.xml', 'rb') as f, mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
    title = pygxml.parse(mm).get("store.book.0.title").to_str()

# Namespace prefix-aware match
pygxml.get(atom_xml, "atom:feed.atom:entry.atom:title").to_str()

# Validate well-formedness without raising.
pygxml.validate(xml)                                        # True

API

Module-level functions

Function Description
get(xml, path) Query xml (str) at path; returns Result
get_bytes(xml, path) Query xml (bytes) at path; returns Result
get_buffer(xml, path) Query xml (buffer protocol) at path; returns Result
get_many(xml, paths) Query xml (str) at each path (str or Path); returns list[Result]
get_many_bytes(xml, paths) Query xml (bytes) at each path (str or Path); returns list[Result]
get_many_buffer(xml, paths) Query xml (buffer protocol) at each path (str or Path); returns list[Result]
parse(xml) Parse the entire XML document into a Result
validate(xml) True if xml is syntactically valid
compile(path) Pre-compile a path expression; returns a Path

Result

get and parse return a Result. Result accessors

Properties

Property Description
r.type_ Python type for this value: None, bool, int, float, str, list, dict
r.value Value converted to the corresponding Python type: None / int / float / str / list[Result] / dict[str, Result]

gjson-style methods

Method Description
r.exists() True if the value was found in the XML
r.to_str() String representation (text content for elements, or full XML for dict/list elements)
r.to_int(),r.to_float() Typed coercions; return 0 / 0.0 when empty
r.to_bool() gjson-style boolean coercion (see below); returns False when empty
r.get(path) Sub-query relative to this value
r.get_many(paths) Sub-query at multiple paths; returns list[Result]

Result.to_bool() follows gjson semantics:

  • "1" / "true" → True; "0" / "false" → False
  • "\"t\"" / "\"T\"" / "\"1\"" → True; "\"f\"" / "\"F\"" / "\"0\"" → False
  • "\"true\"" / "\"TRUE\"" / "\"True\"" → True; "\"false\"" / "\"FALSE\"" / "\"False\"" → False
  • Any other value: to_int() != 0 (non-numeric strings → False)
  • Non-empty dict or list Result → True; empty Result → False

Result.get(path) only descends into element items — scalar items (attributes, #text, counts, modifier aggregates like @sum) have no children, so .get(...) against them yields an empty Result.

Pythonic methods

Syntax Description
str(v),repr(v) dict: <Result type=dict, keys=[...]>; list: <Result type=list, value=[...]>; others: str(v.value)
int(v) 64-bit Integer
float(v) 64-bit float
bool(v) Equivalent to bool(v.value) — False for null/false/0/""/[]/{}
len(v) Chars for String; element count for list/dict elements
v[key] Subscript access
key in v Key membership for dict; string match for list
iter(v) Lazy iterator: chars for str; Results for list; keys for dict
v.keys() Lazy KeysView of dict keys (raises TypeError for non-dict)
v.values() Lazy ValuesView of dict values (raises TypeError for non-dict)
v.items() Lazy ItemsView of (key, Result) pairs (raises TypeError for non-dict)
v.children() Lazy ChildrenView of (name, Result) pairs for every direct child element, in document order (raises TypeError for non-dict)
r == "x", r == ["a", "b"], r == other_result Equality with str/list/Result

Result.items() groups same-named siblings under a single key, so the order between differently named siblings is lost. Result.children() yields one pair per direct child element instead: duplicate names are kept and document order is preserved. Names are raw QNames (namespace prefix included), and text, comments, CDATA and processing instructions are not yielded.

Path

compile(path) returns a Path — a compiled, reusable path expression. Using a pre-compiled Path avoids re-parsing the path string on every call, which matters when querying many documents with the same path.

Method Description
p.get(data) Query XML string data; equivalent to get(data, path)
p.get_bytes(data) Query XML bytes data
p.get_buffer(data) Query buffer-protocol data (mmap, bytearray, memoryview)

Path objects are also accepted wherever a path string is accepted: get_many, get_many_bytes, get_many_buffer, and Result.get_many.

Path syntax

syntax meaning
a.b.c Descend into child elements (local-name match, ignores namespaces)
a.0, a.1 N-th same-named sibling
a.# Count of same-named siblings
a.#.b Project b over all same-named siblings
*, ? Wildcards in element name
@name Attribute reference
#text Explicit text content
\., \@ Escape
a.#(expr) Filter, first match. expr ::= path op value
a.#(expr)# Filter, all matches
path | @modifier Apply modifier (@reverse, @first, @last, @count, @sort, @sort_n, @unique/@uniq, @flatten, @tostr, @sum, @avg/@mean, @min, @max)
prefix:local Prefix-aware match — qualified-name literal compare (matches <atom:title>, not <rss:title>)
a.**.b Descendant: match every b at any depth under a (XPath // equivalent)

A bare child name (no .N/.#/filter) is implicit: at the terminal position it returns every match (a list-shaped Result), but at a non-terminal position the engine raises ValueError if more than one element matches. To chain past a multi-match step, pick one (.0, .1, …) or project explicitly with .#. Single-match elements (e.g., a unique root element) chain transparently.

Result.get(path) follows the same rule: it requires the receiver to hold at most one element. To process every element of a multi-match Result, iterate (for item in result: item.get(...)).

Filter operators: == = != < <= > >= % (glob) !% (negative glob). Filter values: "string", number, true/false, or bare unquoted text.

Inputs

bytes, str, mmap.mmap, bytearray, memoryview — anything implementing the buffer protocol. bytes and mmap are zero-copy on the way in; str is copied once to UTF-8.

pygxml.parse(data) keeps a reference to the input object instead of copying it. Two consequences worth knowing:

  • For mmap input, do not close the mmap while a Result derived from it is still in use — re-borrows during .get() / .str() will fault.
  • For bytearray and other mutable buffers, mutations after parse(...) are observed by subsequent Result accesses.

pygxml.get(data, path) does not retain the input; captured element fragments inside the returned Result are owned copies.

License

MIT

Metadata

Release files for pygxml 0.0.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pygxml 0.0.5
File Size Uploaded
pygxml-0.0.5.tar.gz 61.6 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pygxml 0.0.5
File
pygxml-0.0.5-cp311-abi3-win_arm64.whl CPython 3.11 abi3 Windows ARM64 Details
pygxml-0.0.5-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
pygxml-0.0.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
pygxml-0.0.5-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
pygxml-0.0.5-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
pygxml-0.0.5-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 3.2 MB

Release files / pygxml-0.0.5.tar.gz

Download URL pygxml-0.0.5.tar.gz
Size 61.6 kB
Tags Source
SHA-256 checksum
How to use checksums
6b40d1d6d1fb2ee83f62dad1bef6aa4aaafc0d22edf3aa4b82539926626614dd
BLAKE2b-256 checksum
How to use checksums
6b19556c007de0d0761226fb92891f1b1f9f076d5b872e10f83abca35da47f98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / pygxml-0.0.5-cp311-abi3-win_arm64.whl

Download URL pygxml-0.0.5-cp311-abi3-win_arm64.whl
Size 433.7 kB
Tags CPython 3.11 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
6fa075b1778f5fd298a3f4e33ad1424272c961128a363c74115215ff8a9586a9
BLAKE2b-256 checksum
How to use checksums
1e575c0db7ad70f5f978a851300f58afea507d6ade803c281df56e3c8b8d98ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / pygxml-0.0.5-cp311-abi3-win_amd64.whl

Download URL pygxml-0.0.5-cp311-abi3-win_amd64.whl
Size 448.3 kB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
57a9041bf3d69fda09da5ee51094f7fbd2022c8a804a7ecc6551819862761716
BLAKE2b-256 checksum
How to use checksums
0ea9790a3bd3f9d9948a93d1bc730c2d23a456debcc0b6c7d01dbbc78fffc9cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / pygxml-0.0.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL pygxml-0.0.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 570.9 kB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
6685fffe452ddd2efa845cd905d3ebe9fb9bfe7c5fc1923d92f2185fac544ccb
BLAKE2b-256 checksum
How to use checksums
c8ab46a7d7e5f36db8e81225154018015ab12cfc1cfb491ed5ca2225651f00e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / pygxml-0.0.5-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL pygxml-0.0.5-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 567.3 kB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
dbea98ee943517a80249f986bbede7eb849295d3aa1f65d55b5dca3493c509ac
BLAKE2b-256 checksum
How to use checksums
d66dc81a77a9a2f0cbba9f2ef62a4175be6a6353e77ca18974a45afedaa2ca15
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / pygxml-0.0.5-cp311-abi3-macosx_11_0_arm64.whl

Download URL pygxml-0.0.5-cp311-abi3-macosx_11_0_arm64.whl
Size 532.7 kB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c2e7629b317661ab6d957af752fdd96cbf48e558863d3a3eb0a8276f7c08a830
BLAKE2b-256 checksum
How to use checksums
f0a82851a08461f723bf7e64012fd8ad2a4007a914f8af43bf6f81644b58a5d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / pygxml-0.0.5-cp311-abi3-macosx_10_12_x86_64.whl

Download URL pygxml-0.0.5-cp311-abi3-macosx_10_12_x86_64.whl
Size 544.5 kB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
027a5be906879a88e58180c983076b4c56bcde8471a04349effeeaad34076f63
BLAKE2b-256 checksum
How to use checksums
0b6e87bbf97758c9b88afa345113b5ae4a2a77945d059510918c6a5b3dbd0569
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.5 This release

7 release files

0.0.4

7 release files

0.0.3

7 release files

0.0.2

7 release files

0.0.1

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page