streaming parser using gjson-style path queries over XML
Project description
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
# 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) |
r == "x", r == ["a", "b"], r == other_result |
Equality with str/list/Result |
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
mmapinput, do not close the mmap while a Result derived from it is still in use — re-borrows during.get()/.str()will fault. - For
bytearrayand other mutable buffers, mutations afterparse(...)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
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pygxml-0.0.4.tar.gz.
File metadata
- Download URL: pygxml-0.0.4.tar.gz
- Upload date:
- Size: 60.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07e402f46c006d325739d5e6d78641855676ee0dfe5533643e0fc54a02556aec
|
|
| MD5 |
0451eaba1c477c162b5b40b69404fff4
|
|
| BLAKE2b-256 |
cdd90053bccd38d5dcba45c9e025999b14f8b1dc9ffe4ffec98c200b65511ee1
|
Provenance
The following attestation bundles were made for pygxml-0.0.4.tar.gz:
Publisher:
publish.yml on minefuto/pygxml
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygxml-0.0.4.tar.gz -
Subject digest:
07e402f46c006d325739d5e6d78641855676ee0dfe5533643e0fc54a02556aec - Sigstore transparency entry: 2047469032
- Sigstore integration time:
-
Permalink:
minefuto/pygxml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Branch / Tag:
refs/tags/v0.0.4 - Owner: https://github.com/minefuto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Trigger Event:
push
-
Statement type:
File details
Details for the file pygxml-0.0.4-cp311-abi3-win_arm64.whl.
File metadata
- Download URL: pygxml-0.0.4-cp311-abi3-win_arm64.whl
- Upload date:
- Size: 433.0 kB
- Tags: CPython 3.11+, Windows ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0821609e59b0ea7523fa15710abca3f0579ec2338abf48407306a262efa5574b
|
|
| MD5 |
2631094aa54a4283239fb97d5a4bfeaa
|
|
| BLAKE2b-256 |
0394994dfd01388e6fdfd4146959f7ed8fe53ae8f29c0a7e64bfdbd0773a42f9
|
Provenance
The following attestation bundles were made for pygxml-0.0.4-cp311-abi3-win_arm64.whl:
Publisher:
publish.yml on minefuto/pygxml
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygxml-0.0.4-cp311-abi3-win_arm64.whl -
Subject digest:
0821609e59b0ea7523fa15710abca3f0579ec2338abf48407306a262efa5574b - Sigstore transparency entry: 2047469075
- Sigstore integration time:
-
Permalink:
minefuto/pygxml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Branch / Tag:
refs/tags/v0.0.4 - Owner: https://github.com/minefuto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Trigger Event:
push
-
Statement type:
File details
Details for the file pygxml-0.0.4-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: pygxml-0.0.4-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 445.8 kB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99c864fa89f7453b59d68a870c07f5ec28b232aa0b0d72eebcfd5008d35db11b
|
|
| MD5 |
97055897db2f949cf2cac0be3d40ecb3
|
|
| BLAKE2b-256 |
c0b2f137a5eedde8828349ea1d80cba9af30e94562fa06c0a4f13683dc71589d
|
Provenance
The following attestation bundles were made for pygxml-0.0.4-cp311-abi3-win_amd64.whl:
Publisher:
publish.yml on minefuto/pygxml
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygxml-0.0.4-cp311-abi3-win_amd64.whl -
Subject digest:
99c864fa89f7453b59d68a870c07f5ec28b232aa0b0d72eebcfd5008d35db11b - Sigstore transparency entry: 2047469064
- Sigstore integration time:
-
Permalink:
minefuto/pygxml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Branch / Tag:
refs/tags/v0.0.4 - Owner: https://github.com/minefuto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Trigger Event:
push
-
Statement type:
File details
Details for the file pygxml-0.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pygxml-0.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 573.0 kB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd23c0cb46b5a95cc02c1b4e033192dbc49ea3849573207790dceb7fae5063b6
|
|
| MD5 |
1948a498cda588a076dff57e44159187
|
|
| BLAKE2b-256 |
4a050642a94a0e029c1f85665add7ae2bcd024fae7cb775ce69770cd283656f4
|
Provenance
The following attestation bundles were made for pygxml-0.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish.yml on minefuto/pygxml
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygxml-0.0.4-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
cd23c0cb46b5a95cc02c1b4e033192dbc49ea3849573207790dceb7fae5063b6 - Sigstore transparency entry: 2047469082
- Sigstore integration time:
-
Permalink:
minefuto/pygxml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Branch / Tag:
refs/tags/v0.0.4 - Owner: https://github.com/minefuto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Trigger Event:
push
-
Statement type:
File details
Details for the file pygxml-0.0.4-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pygxml-0.0.4-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 569.2 kB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c5ce8dfca81aace7e0a60d65f82ef07b1851df8bf100859136202e5f8891718
|
|
| MD5 |
41713b1060b3076200fe16b764befbf6
|
|
| BLAKE2b-256 |
0f08212d3ce7b6e0fcc4b6c5b81e43969e0d7800550a373fc70df7f38d14a422
|
Provenance
The following attestation bundles were made for pygxml-0.0.4-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish.yml on minefuto/pygxml
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygxml-0.0.4-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
7c5ce8dfca81aace7e0a60d65f82ef07b1851df8bf100859136202e5f8891718 - Sigstore transparency entry: 2047469050
- Sigstore integration time:
-
Permalink:
minefuto/pygxml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Branch / Tag:
refs/tags/v0.0.4 - Owner: https://github.com/minefuto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Trigger Event:
push
-
Statement type:
File details
Details for the file pygxml-0.0.4-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: pygxml-0.0.4-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 534.5 kB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e5e45c26ab3a07cccd74285b295d71a2524df8db79d6de515a9fa16ec69c19c3
|
|
| MD5 |
60b9d5f8ae801360a2ea43d09720e70d
|
|
| BLAKE2b-256 |
e8c8be29efec245e55a3365978cf95f1a1e33e065619a13098a94755b352d565
|
Provenance
The following attestation bundles were made for pygxml-0.0.4-cp311-abi3-macosx_11_0_arm64.whl:
Publisher:
publish.yml on minefuto/pygxml
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygxml-0.0.4-cp311-abi3-macosx_11_0_arm64.whl -
Subject digest:
e5e45c26ab3a07cccd74285b295d71a2524df8db79d6de515a9fa16ec69c19c3 - Sigstore transparency entry: 2047469058
- Sigstore integration time:
-
Permalink:
minefuto/pygxml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Branch / Tag:
refs/tags/v0.0.4 - Owner: https://github.com/minefuto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Trigger Event:
push
-
Statement type:
File details
Details for the file pygxml-0.0.4-cp311-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: pygxml-0.0.4-cp311-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 546.2 kB
- Tags: CPython 3.11+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
144da41f5acc4c4715e6f001e7a9cf0f425bd47de414c2005997df1de8f334f1
|
|
| MD5 |
5c716fa27eb0ed7b9a0e01b3b3b04283
|
|
| BLAKE2b-256 |
8a0bbeb1888f3f4012a507c86c053735f4fb41389fc30a86f8974d96d76d8ce3
|
Provenance
The following attestation bundles were made for pygxml-0.0.4-cp311-abi3-macosx_10_12_x86_64.whl:
Publisher:
publish.yml on minefuto/pygxml
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pygxml-0.0.4-cp311-abi3-macosx_10_12_x86_64.whl -
Subject digest:
144da41f5acc4c4715e6f001e7a9cf0f425bd47de414c2005997df1de8f334f1 - Sigstore transparency entry: 2047469038
- Sigstore integration time:
-
Permalink:
minefuto/pygxml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Branch / Tag:
refs/tags/v0.0.4 - Owner: https://github.com/minefuto
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d823821df5f6e6a022b454a2d238b4c5f8cb9d4c -
Trigger Event:
push
-
Statement type: