API Reference

This page documents every public class, method, property, and function in pygixml. For high-level usage guides see Quick Start, Objectify — Dotted Navigation, and Dictify — XML to Dict.


Core Module

pygixml - Python wrapper for pugixml using Cython

A fast and efficient XML parser and manipulator for Python.

exception pygixml.PygiXMLError

Bases: ValueError

Raised when a pygixml operation fails.

Typical causes include malformed XML passed to parse_string() or parse_file(), or an attempt to set a name/value on a null or otherwise invalid node.

exception pygixml.PygiXMLNullNodeError

Bases: PygiXMLError

Raised when an operation that requires a valid node is called on a null node (e.g. setting attributes on an element that was never found).

class pygixml.ParseFlags(value)

Bases: IntFlag

Bitmask of parse options for parse_string() and parse_file().

Members are combined with the bitwise OR operator (|). When no flags are supplied the parser uses ParseFlags.DEFAULT (all standard processing enabled).

Use ParseFlags.MINIMAL when you only care about element structure and want the fastest possible parse — it skips escape processing, EOL normalization, and all whitespace handling.

Example:

>>> doc = pygixml.parse_string(xml, pygixml.ParseFlags.MINIMAL)
>>> # Combine specific flags:
>>> flags = pygixml.ParseFlags.COMMENTS | pygixml.ParseFlags.CDATA
>>> doc = pygixml.parse_string(xml, flags)

See the Parse Flags section in the documentation for a complete description of each flag.

CDATA = 4
COMMENTS = 2
DECLARATION = 256
DEFAULT = 116
DOCTYPE = 512
EMBED_PCDATA = 8192
EOL = 32
ESCAPES = 16
FRAGMENT = 4096
FULL = 887
MERGE_PCDATA = 16384
MINIMAL = 0
PI = 1
TRIM_PCDATA = 2048
WCONV_ATTRIBUTE = 64
WNORM_ATTRIBUTE = 128
WS_PCDATA = 8
WS_PCDATA_SINGLE = 1024
class pygixml.XMLAttribute

Bases: object

An XML attribute on an element (e.g. id="123").

Use XMLNode.attribute() or XMLNode.first_attribute() to obtain attributes.

Example:

>>> doc = pygixml.parse_string('<root id="42" class="main"/>')
>>> root = doc.root
>>> root.attribute('id').value
'42'
set_name(name)

Change the attribute name. Returns False if null.

set_value(value)

Change the attribute value. Returns False if null.

name

Return the attribute name.

Returns:

str | None

next_attribute

Get next attribute.

Returns:

Next attribute or None if no next attribute

Return type:

XMLAttribute

Example

>>> attr = node.first_attribute()
>>> next_attr = attr.next_attribute
value

Return the attribute value.

Returns:

str | None

class pygixml.XMLDocument

Bases: object

An XML document, providing document-level operations.

Use this class to load, create, save, and manipulate XML documents, or to access the root element and top-level children.

The most common entry point is parse_string() or parse_file(), which return an XMLDocument:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> doc.root.child('item').text()
'value'

You can also build a document from scratch:

>>> doc = pygixml.XMLDocument()
>>> root = doc.append_child('catalog')
>>> item = root.append_child('item')
>>> item.set_value('content')

When processing many files in a loop, reuse a single document with reset() to avoid repeated allocations.

append_child(name)

Append a new child element and return it.

Parameters:

name (str) – Tag name for the new element. Pass an empty string to create a text node instead.

Returns:

The newly created element (or text node).

Return type:

XMLNode

Example:

>>> doc = pygixml.XMLDocument()
>>> root = doc.append_child('catalog')
>>> item = root.append_child('item')
>>> item.set_value('content')
child(name)

Return the first child element whose tag matches name, or None if no match is found.

Parameters:

name (str) – Element tag to look for.

Returns:

XMLNode | None

Example:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> doc.child('item').text()
'value'
first_child()

Return the first child element, or None if the document is empty.

Returns:

XMLNode | None

Example:

>>> doc = pygixml.parse_string('<root><child/></root>')
>>> doc.first_child().name
'root'
load_file(path, options=4294967295)

Parse XML from a file and replace the current document content.

Reads and parses the file at path. Returns True on success, False if the file cannot be opened or does not contain well-formed XML.

Parameters:
  • path (str) – Path to the XML file.

  • options (ParseFlags) – Which parse flags to use. Defaults to ParseFlags.DEFAULT.

Returns:

True if loading succeeded, False otherwise.

Return type:

bool

Example:

>>> doc = pygixml.XMLDocument()
>>> doc.load_file('data.xml')
True
>>> doc.root.name
'root'
load_string(content, options=4294967295)

Parse XML from a string and replace the current document content.

Parses content and replaces whatever the document previously held. Returns True on success, False if the string is not well-formed.

Parameters:
  • content (str) – The XML source text.

  • options (ParseFlags) – Which parse flags to use. Defaults to ParseFlags.DEFAULT (full compliance). Use ParseFlags.MINIMAL for faster parsing when you don’t need escape processing, EOL normalization, or whitespace handling.

Returns:

True if parsing succeeded, False otherwise.

Return type:

bool

Example:

>>> doc = pygixml.XMLDocument()
>>> doc.load_string('<root><item>value</item></root>')
True
>>> doc.root.child('item').text()
'value'
Raises:

PygiXMLError – When the input is not well-formed XML (raised by parse_string(); this method returns False instead).

reset()

Clear all content, returning the document to its initial empty state.

Reuses the same underlying C++ document object, avoiding reallocation overhead when processing many files in a loop.

Example:

>>> doc = pygixml.parse_string('<root>content</root>')
>>> doc.reset()
>>> doc.root  # None — document is empty
save_file(path, indent='  ')

Serialize the document and write it to a file.

Parameters:
  • path (str) – Output file path. Existing files will be overwritten.

  • indent (str) – Indentation string used for pretty-printing. Defaults to two spaces. Pass an empty string for compact output with no indentation.

Example:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> doc.save_file('output.xml')              # 2-space indent
>>> doc.save_file('compact.xml', indent='')  # no indent
to_string(indent='  ')

Serialize the document to an XML string.

Parameters:

indent (str | int) – Indentation — either a string (e.g. '    ') or a number of spaces (e.g. 4). Defaults to two spaces.

Returns:

The serialized XML.

Return type:

str

Example:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> doc.to_string()
'<root>\n  <item>value</item>\n</root>'
>>> doc.to_string(4)
'<root>\n    <item>value</item>\n</root>'
root

Return the root element of the document.

Equivalent to calling first_child(). Returns None if the document is empty.

Returns:

The root element, or None.

Return type:

XMLNode | None

Example:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> doc.root.name
'root'
class pygixml.XMLNode

Bases: object

A single node in the XML tree.

Represents an element, text, comment, processing instruction, or other node type. Provides methods for navigating to related nodes (parent, children, siblings), reading and modifying content, and executing XPath queries scoped to this node.

The most commonly used members are:

Example:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> root = doc.root
>>> root.child('item').text()
'value'
static from_mem_id_unsafe(mem_id)

Reconstruct an XMLNode from its memory identifier in O(1) time.

Unlike find_mem_id(), which walks the entire tree in O(n) time to locate a node, this method performs an instant lookup.

⚠️ Warning: If the mem_id is stale (the node was deleted or the document has been freed), calling methods on the returned object may cause a segmentation fault.

Only use this when you are certain the identifier still belongs to a live node within a valid XMLDocument.

Parameters:

mem_id (int) – An identifier previously obtained from node.mem_id.

Returns:

A wrapper for the node at the given identifier.

Return type:

XMLNode

Complexity:

O(1) — direct lookup, no tree traversal. Compare with find_mem_id() which is O(n).

Example:

>>> mid = root.child('item').mem_id
>>> node = XMLNode.from_mem_id_unsafe(mid)
>>> node.name
'item'
append_attribute(name)

Append a new attribute and return it.

Parameters:

name (str) – Attribute name.

Returns:

The newly created attribute.

Return type:

XMLAttribute

Example:

>>> root = doc.root
>>> attr = root.append_attribute('id')
>>> attr.value = '123'
append_child(name)

Append a new child element and return it.

Parameters:

name (str) – Tag name. Use an empty string to create a text node instead.

Returns:

The newly created child.

Return type:

XMLNode

Example:

>>> root = doc.root
>>> root.append_child('title').set_value('My Title')
attribute(name)

Return the attribute with the given name, or None.

Parameters:

name (str) – Attribute name.

Returns:

XMLAttribute | None

Example:

>>> doc = pygixml.parse_string('<root id="1"/>')
>>> doc.root.attribute('id').value
'1'
child(name)

Return the first child element whose tag matches name, or None.

Parameters:

name (str) – Element tag to look for.

Returns:

XMLNode | None

Example:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> doc.root.child('item').text()
'value'
child_value(name=None)

Return the text content of a child element.

If name is given, finds the first child with that tag and returns its text. Without name, returns the direct text content of this node (i.e. text immediately inside this element, not inside a child).

Parameters:

name (str | None) – Child tag to look up, or None for direct text.

Returns:

str | None

Example:

>>> doc = pygixml.parse_string('<root><title>Book</title></root>')
>>> doc.root.child_value('title')
'Book'
children(recursive=False)

Iterate over child element nodes.

Note

This is a pygixml-specific feature. pugixml provides first_child() and next_sibling() for manual traversal, but children() offers a Pythonic one-liner for iterating direct child elements — or all descendants with recursive=True.

Text, comment, and processing-instruction nodes are skipped.

Parameters:

recursive (bool) – Yield only direct children (False, the default) or all descendants in depth-first order (True).

Yields:

XMLNode

Example:

>>> doc = pygixml.parse_string('<root><a><a1/></a><b/></root>')
>>> [c.name for c in doc.root.children()]
['a', 'b']
>>> [c.name for c in doc.root.children(True)]
['a', 'a1', 'b']
find_mem_id(mem_id)

Look up a descendant node by its memory identifier (see mem_id).

Note

This is a pygixml-specific feature. pugixml has no equivalent — pygixml walks the descendant tree in DFS order comparing node addresses until a match is found.

Returns:

XMLNode | None

first_attribute()

Return the first attribute on this element, or None if it has none.

Returns:

XMLAttribute | None

Example:

>>> doc = pygixml.parse_string('<root id="1" class="main"/>')
>>> doc.root.first_attribute().name
'id'
first_child()

Return the first child element, or None.

Returns:

XMLNode | None

Example:

>>> doc = pygixml.parse_string('<root><a/><b/></root>')
>>> doc.root.first_child().name
'a'
is_null()

Return True if this node is null (i.e. was not found or is invalid).

prepend_attribute(name)

Prepend a new attribute and return it.

Parameters:

name (str) – Attribute name.

Returns:

The newly created attribute.

Return type:

XMLAttribute

Example:

>>> root = doc.root
>>> attr = root.prepend_attribute('id')
>>> attr.value = '123'
prepend_child(name)

Preppend a new child element and return it.

Parameters:

name (str) – Tag name. Use an empty string to create a text node instead.

Returns:

The newly created child.

Return type:

XMLNode

Example:

>>> root = doc.root
>>> root.preppend_child('title').set_value('My Title')
remove_attribute(attr)

Remove an attribute from this node.

Parameters:

attr (XMLAttribute) – The attribute to remove.

Returns:

True if the attribute was successfully removed, False otherwise.

Return type:

bool

Example:

>>> root = doc.root
>>> attr = root.attribute('id')
>>> root.remove_attribute(attr)
True
remove_child(node)

Remove a direct child element from this node.

Parameters:

node (XMLNode) – The child node to remove. Must be a direct child of this node.

Returns:

True if the node was successfully removed, False otherwise.

Return type:

bool

Example:

>>> child = root.child('old_item')
>>> if child:
...     root.remove_child(child)
select_node(query)

Run an XPath expression and return the first match, or None.

Parameters:

query (str) – XPath 1.0 expression.

Returns:

XPathNode | None

Example:

>>> doc = pygixml.parse_string('<root><a/><b/></root>')
>>> doc.root.select_node('b').node.name
'b'
select_nodes(query)

Run an XPath expression and return all matching nodes.

Parameters:

query (str) – XPath 1.0 expression.

Returns:

XPathNodeSet

Example:

>>> doc = pygixml.parse_string('<root><a/><b/><a/></root>')
>>> len(doc.root.select_nodes('a'))
2
set_name(name)

Change the tag name of this element.

Returns False if the node is null.

Parameters:

name (str) – New tag name.

Returns:

bool

Example:

>>> doc = pygixml.parse_string('<old/>')
>>> doc.root.set_name('new')
True
>>> doc.root.name
'new'
set_value(value)

Replace the text content of this node.

Returns False if the node is null.

Parameters:

value (str) – New text content.

Returns:

bool

Example:

>>> doc = pygixml.parse_string('<root><item>old</item></root>')
>>> doc.root.child('item').first_child().set_value('new')
True
text(recursive=True, join='\n')

Return the combined text content of this node.

Note

This is a pygixml-specific feature. pugixml provides child_value() for a single child’s text, but text() recursively collects text from all descendants (optionally non-recursive) and joins the fragments with a configurable separator.

Parameters:
  • recursive (bool) – When True (default), gathers text from all descendant text and CDATA nodes. When False, returns only text that is a direct child of this element.

  • join (str) – String used to join multiple text fragments. Defaults to \n.

Returns:

str

Example:

>>> doc = pygixml.parse_string(
...     '<root><a>hello</a><b>world</b></root>')
>>> doc.root.text()
'hello\nworld'
>>> doc.root.text(join=', ')
'hello, world'
to_string(indent='  ')

Serialize this element (and its subtree) to an XML string.

Note

This is a pygixml-specific feature. pugixml can serialize to a file via save_file(), but it does not provide a method that returns the serialized XML as a Python string. pygixml implements this using an internal std::ostringstream buffer.

Parameters:

indent (str | int) – Indentation string or number of spaces. Defaults to two spaces.

Returns:

str

Example:

>>> doc = pygixml.parse_string('<root><item>val</item></root>')
>>> doc.root.child('item').to_string()
'<item>val</item>'
mem_id

A unique numeric identifier derived from the node’s internal address.

Note

This is a pygixml-specific feature. The underlying pugixml library does not expose integer node identifiers natively. pygixml provides mem_id as a safe, hashable handle for debugging, caching, and fast node reconstruction.

Returns 0 for null nodes.

Returns:

int

name

Return the tag name of this node.

For element nodes this is the element’s tag name. For text, comment, and other non-element nodes this is None.

Returns:

str | None

Example:

>>> doc = pygixml.parse_string('<root/>')
>>> doc.root.name
'root'
next_element_sibling

The next sibling that is an element node, skipping text, comment, and other non-element nodes. None if none.

next_sibling

The next sibling node, or None if this is the last child.

parent

The parent element node. Returns None for the document root.

previous_element_sibling

The previous sibling that is an element node. None if none.

previous_sibling

The previous sibling node, or None if this is the first child.

type

Return the node type as a human-readable string.

Possible values: 'element', 'pcdata', 'cdata', 'comment', 'pi', 'declaration', 'doctype', 'document', 'null'.

Returns:

str

Example:

>>> doc = pygixml.parse_string('<root>text</root>')
>>> doc.root.type
'element'
>>> doc.root.first_child().type
'pcdata'
value

Return the text content of this node.

For text, CDATA, comment, and processing-instruction nodes, returns the raw value directly.

For element nodes, this is a convenience shortcut that returns the value of the first text/CDATA child (or None if no text child exists).

Returns:

str | None

Example:

# Text node — returns raw value
>>> doc = pygixml.parse_string('<root><item>hello</item></root>')
>>> doc.root.child('item').first_child().value
'hello'

# Element node — returns first text child's value
>>> doc.root.child('item').value
'hello'
xml

Shorthand for self.to_string() — serialized XML with default two-space indentation.

Note

This is a pygixml-specific convenience property. pugixml has no equivalent.

xpath

The absolute XPath to this node (e.g. /root/item[1]/name[1]).

Note

This is a pygixml-specific feature. pugixml does not provide XPath generation natively — pygixml implements a custom O(depth) algorithm that walks from the node up to the root, counting same-name siblings to produce accurate positional predicates.

Returns an empty string if the node is not an element.

Returns:

str

class pygixml.XPathNode

Bases: object

A single result from an XPath query.

Wraps either an XMLNode (.node) or an XMLAttribute (.attribute). One of these properties will be None depending on what the query matched.

Example:

>>> doc = pygixml.parse_string('<root><item id="1">value</item></root>')
>>> result = doc.select_node('//item')
>>> result.node.name
'item'
attribute

The matched attribute, or None if the query matched an element instead.

node

The matched element, or None if the query matched an attribute instead.

parent

The parent of the matched node (None for attributes or the document root).

class pygixml.XPathNodeSet

Bases: object

A collection of XPathNode results from an XPath query.

Supports len(), indexing (node_set[0]), and iteration.

Example:

>>> doc = pygixml.parse_string('<root><item>1</item><item>2</item></root>')
>>> nodes = doc.select_nodes('//item')
>>> len(nodes)
2
>>> nodes[0].node.text()
'1'
class pygixml.XPathQuery

Bases: object

A compiled XPath 1.0 query.

Compiling a query once and re-using it is faster than calling select_nodes() repeatedly, because the expression is parsed only once.

Example:

>>> doc = pygixml.parse_string('<root><item>value</item></root>')
>>> query = pygixml.XPathQuery('//item')
>>> query.evaluate_node(doc.root).node.text()
'value'
evaluate_boolean(context_node)

Evaluate query and return boolean result.

Parameters:

context_node (XMLNode) – Node to evaluate the query against

Returns:

Boolean result of the XPath query

Return type:

bool

Example

>>> query = pygixml.XPathQuery('count(//item) > 0')
>>> has_items = query.evaluate_boolean(doc.first_child())
>>> print(has_items)
True
evaluate_node(context_node)

Evaluate query and return first node.

Parameters:

context_node (XMLNode) – Node to evaluate the query against

Returns:

First matching XPath node or None if no matches

Return type:

XPathNode

Example

>>> query = pygixml.XPathQuery('//item')
>>> node = query.evaluate_node(doc.first_child())
>>> print(node.node.text())
evaluate_node_set(context_node)

Evaluate query and return node set.

Parameters:

context_node (XMLNode) – Node to evaluate the query against

Returns:

Set of matching XPath nodes

Return type:

XPathNodeSet

Example

>>> query = pygixml.XPathQuery('//item')
>>> nodes = query.evaluate_node_set(doc.first_child())
>>> for node in nodes:
...     print(node.node.text())
evaluate_number(context_node)

Evaluate query and return numeric result.

Parameters:

context_node (XMLNode) – Node to evaluate the query against

Returns:

Numeric result of the XPath query

Return type:

float

Example

>>> query = pygixml.XPathQuery('count(//item)')
>>> count = query.evaluate_number(doc.first_child())
>>> print(count)
2.0
evaluate_string(context_node)

Evaluate query and return string result.

Parameters:

context_node (XMLNode) – Node to evaluate the query against

Returns:

String result of the XPath query or None if empty

Return type:

str

Example

>>> query = pygixml.XPathQuery('//item[1]/text()')
>>> text = query.evaluate_string(doc.first_child())
>>> print(text)
'value'
pygixml.iterfind(source, tag, stack_size=4096, chunk_size=65536)

Shortcut for iterparse(source, events=("end",), tag=tag) that yields StreamElement objects directly (no (event, elem) tuples).

Example:

for record in pygixml.iterfind("big.xml", "record"):
    handle(record)
    record.clear()
pygixml.iterparse(source, events=('end',), tag=None, stack_size=4096, chunk_size=65536)

Incrementally parse a (possibly huge) XML document.

Yields (event, element) pairs as each element completes, where element is a StreamElement. This never loads the whole document into a pugixml tree; only the PullParser’s lightweight element objects are kept.

Parameters:
  • source – a file path (str/os.PathLike), a binary file-like object (anything with .read(n)), or raw XML bytes/bytearray.

  • events – subset of ("start", "end", "pi"). Default ("end",), matching xml.etree.ElementTree.

  • tag – if given, only elements with this tag produce events (their subtrees are still built normally).

  • stack_size – see PullParser.

  • chunk_size – how many bytes to read from source at a time.

Example – process every <record> while keeping memory bounded:

for event, elem in pygixml.iterparse("big.xml", events=("end",)):
    if elem.tag == "record":
        handle(elem)
        elem.clear()
pygixml.parse_file(file_path, options=4294967295)

Parse XML from file and return XMLDocument.

Parameters:
  • file_path (str) – Path to XML file

  • options (ParseFlags, optional) – Parse flags (default: ParseFlags.DEFAULT). Combine flags with bitwise OR. Use ParseFlags.MINIMAL for fastest parsing when you don’t need comments, CDATA, or escape processing.

Returns:

Parsed XML document

Return type:

XMLDocument

Raises:

PygiXMLError – If parsing fails

Example

>>> import pygixml
>>> doc = pygixml.parse_file('data.xml')
>>> doc = pygixml.parse_file('data.xml', pygixml.ParseFlags.MINIMAL)
pygixml.parse_string(xml_string, options=4294967295)

Parse XML from string and return XMLDocument.

Parameters:
  • xml_string (str) – XML content as string

  • options (ParseFlags, optional) – Parse flags (default: ParseFlags.DEFAULT). Combine flags with bitwise OR. Use ParseFlags.MINIMAL for fastest parsing when you don’t need comments, CDATA, or escape processing.

Returns:

Parsed XML document

Return type:

XMLDocument

Raises:

PygiXMLError – If parsing fails

Example

>>> import pygixml
>>> doc = pygixml.parse_string('<root>content</root>')
>>> doc = pygixml.parse_string(xml, pygixml.ParseFlags.MINIMAL)

objectify

pygixml.objectify — lxml.objectify-style interface.

All logic lives in objectify.pxi and namespace.pxi, compiled into pygixml_cy.so.

Usage:

from pygixml import objectify

# Plain XML
root = objectify.from_string(xml)
root = objectify.from_file(path)

# Namespace-aware (auto-detected from xmlns declarations)
root = objectify.from_string(xml)
root.find("{http://ns.com}item")   # Clark notation
root.find("ns:item")               # prefix notation
root.ns_item                       # dotted access

# Explicit namespace map
root = objectify.from_string(xml, namespaces={"dc": "http://dc.com"})
root.dc_title
class pygixml.objectify.AttributeMap

Bases: object

Dict-like view of all XML attributes on a node.

Provides attribute access via dotted notation, indexing, iteration, and safe get(). Each access returns a lazy AttributeValue — no string conversion until you ask for it.

Access patterns

  • am.idAttributeValue for attribute id

  • am["id"] — same via __getitem__

  • am.get("id")AttributeValue or default

  • str(am.id) — raw string value

  • am.id() — type-inferred value

  • for av in am — iterate all attributes as AttributeValue

  • len(am) — number of attributes

  • "id" in am — membership test

  • am.keys() — list of attribute names

  • am.values() — list of AttributeValue objects

  • am.items() — list of (name, AttributeValue) tuples

  • dict(am){name: str_value} plain dict

get(name, default=None)

Return AttributeValue for name, or default if absent.

items()

List of (name, AttributeValue) tuples.

keys()

List of attribute names.

to_dict(type_infer=False)

Return a plain {name: value} dict.

Parameters:

type_infer – If True, values are type-inferred (bool/int/float/str). If False (default), all values are plain str.

values()

List of AttributeValue objects.

class pygixml.objectify.AttributeValue

Bases: object

Lazy wrapper around a single XML attribute.

Holds the C-level xml_attribute struct directly — no string copy or type conversion is performed until explicitly requested.

Access patterns

  • str(av) — raw value as str (cheap: one UTF-8 decode)

  • av() — type-inferred value (bool > int > float > str)

  • av.str() — explicit str

  • av.int() — explicit int

  • av.float() — explicit float

  • av.bool() — explicit bool

  • av.name — attribute name as str

  • av.raw — raw bytes (no decode — zero-cost)

All conversion methods accept an optional encoding parameter (default "utf-8").

str()

Return the attribute value as a str.

Equivalent to str(av). Provided for explicit, readable code.

name

Attribute name as a str.

raw

Raw attribute value as bytes — zero-cost, no decode.

class pygixml.objectify.NamespacedElement

Bases: ObjectifiedElement

An ObjectifiedElement with namespace-aware lookup.

Created automatically by objectify_from_string() / objectify_from_file() when a namespaces dict is supplied, or when the document contains xmlns declarations and auto_ns=True (default).

Supports all three lookup styles:

# Clark notation
root.find("{http://ns.com}item")

# Prefix notation (colon via find/findall)
root.find("ns:item")

# Dotted access with registered prefix
root.ns_item          # expands to <ns:item>

The ns_map is inherited by every child element automatically — you never need to pass it manually.

find(tag, recursive=True)

Namespace-aware find. Accepts Clark notation, prefix notation, or plain names. See ObjectifiedElement.find().

findall(tag, recursive=True)

Namespace-aware findall. Accepts Clark notation, prefix notation, or plain names. See ObjectifiedElement.findall().

ns_map

The namespace map {prefix: uri} active for this element.

pygixml.objectify.from_file(path, namespaces=None, auto_ns=True, encoding='auto')

Parse an XML file and return the root as ObjectifiedElement or NamespacedElement.

Parameters:
  • path (str) – Filesystem path to the XML file.

  • namespaces (dict | None) – Optional {prefix: uri} map.

  • auto_ns (bool) – Automatically extract xmlns declarations (default True).

  • encoding (str) – Input encoding hint. Default "auto" (detect from BOM or XML declaration). Other values: "utf-8", "utf-16", "latin-1", etc.

Returns:

Document root.

Return type:

NamespacedElement | ObjectifiedElement

Raises:

PygiXMLError – If the file cannot be read, is malformed, or empty.

Example:

root = objectify_from_file("data.xml")
root = objectify_from_file("legacy.xml", encoding="latin-1")
pygixml.objectify.from_node(node, namespaces=None, auto_ns=True)

Wrap an existing XMLNode as an ObjectifiedElement.

No re-parsing is done — the node’s owning document stays alive via the node’s own reference. Useful when you already have a parsed tree and want to switch to the objectify navigation API for a subtree.

Parameters:
  • node (XMLNode) – A node from a parsed XMLDocument.

  • namespaces (dict | None) – Optional {prefix: uri} map.

  • auto_ns (bool) – Automatically extract xmlns declarations (default True).

Returns:

Wrapped node.

Return type:

NamespacedElement | ObjectifiedElement

Raises:
  • TypeError – If node is not an XMLNode.

  • PygiXMLError – If node is null.

Example:

doc  = pygixml.parse_string(xml)
root = objectify.from_node(doc.root)
print(root.user_profile.first_name)

# wrap a specific child
child = doc.root.child("user-profile")
elem  = objectify.from_node(child)
print(elem.first_name)
pygixml.objectify.from_string(xml, namespaces=None, auto_ns=True, encoding='auto')

Parse an XML string and return the root as ObjectifiedElement or NamespacedElement.

Parameters:
  • xml (str) – XML source text.

  • namespaces (dict | None) – Optional {prefix: uri} map supplied by the caller. Merged with any xmlns declarations found in the document when auto_ns is True.

  • auto_ns (bool) – When True (default), automatically extract xmlns declarations from the root element and use NamespacedElement. Set to False to get a plain ObjectifiedElement` regardless of namespace declarations.

  • encoding (str) – Input encoding hint. Default "auto" (detect from BOM or XML declaration). Other values: "utf-8", "utf-16", "latin-1", etc.

Returns:

Document root.

Return type:

NamespacedElement | ObjectifiedElement

Raises:

PygiXMLError – If the XML is malformed or has no root element.

Example:

root = objectify_from_string(xml)
root = objectify_from_string(xml, encoding="latin-1")
root = objectify_from_string(xml, namespaces={"dc": "http://dc.com"})
class pygixml.objectify.ObjectifiedElement

Wraps an XML element node with attribute-style navigation.

Stores the pugixml xml_node struct directly as a C-level field. _doc_ref keeps the owning XMLDocument alive. _nsmap holds the inherited namespace map for this node (prefix→uri and uri→prefix entries merged together).

Namespace support

xmlns declarations are collected automatically during parsing and propagated to child wrappers. Three tag formats are accepted:

root.ns_item                    # underscore → colon mapping
root.find("ns:item")            # explicit prefix
root.find("{http://ns.com}item")# Clark notation

Write support

Assignment updates child text or attributes; deletion removes them.

__bool__()

True if self else False

__call__()

Type-inferred text content; None for empty/structural nodes.

__eq__(value, /)

Return self==value.

__iter__()

Iterate over direct child element nodes.

__len__()

Return len(self).

__str__()

Raw text content, always a plain str.

find(tag, recursive=True)

Return the first descendant matching tag, or None.

Accepts three tag formats:

  • "item" — plain tag name

  • "ns:item" — prefixed tag name

  • "{http://ns.com}item"— Clark notation (resolved via nsmap)

Parameters:
  • tag (str) – Tag to search for.

  • recursive (bool) – Search all descendants (default True).

Returns:

ObjectifiedElement | None

findall(tag, recursive=True)

Return all descendants matching tag in document order.

Accepts the same tag formats as find().

Parameters:
  • tag (str) – Tag to search for.

  • recursive (bool) – Search all descendants (default True).

Returns:

list[ObjectifiedElement]

get(name, default=None)

Return the value of attribute name, or default if absent.

Never raises. Underscore→hyphen fallback applies. Namespace prefix mapping applies when a namespace map is present.

Parameters:
  • name (str) – Attribute name.

  • default – Returned when absent. Defaults to None.

attrib

All attributes as an AttributeMap.

xmlns declarations are excluded — use nsmap for those.

Example:

root.attrib["id"]          # type-inferred value
root.attrib.id             # same via dotted access
str(root.attrib["id"])     # as string
for k, v in root.attrib.items(): ...
local_name

Tag name without namespace prefix (str).

Example:

# For <ns:item>, tag = "ns:item", local_name = "item"
namespace

Namespace URI of this element, or None if not in any namespace.

Resolved via the inherited namespace map.

Example:

root = objectify_from_string(
    '<root xmlns:ns="http://ns.com"><ns:item/></root>')
root.ns_item.namespace   # 'http://ns.com'
nsmap

{prefix: uri}.

Only prefix→uri entries are returned (not the reverse uri→prefix entries that are stored internally for lookup purposes).

Example:

root = objectify_from_string(
    '<root xmlns:ns="http://ns.com"><ns:item/></root>')
root.nsmap   # {'ns': 'http://ns.com', '': 'http://default.com'}
Type:

Namespace map for this element

prefix

Namespace prefix of this element, or None if unprefixed.

Example:

# For <ns:item>, prefix = "ns"
tag

The XML tag name of this element (str).

text_content

Raw text content, always a str.

xml

Serialised XML of this node and its subtree.

class pygixml.objectify.NodeSequence

A sequence of ObjectifiedElement siblings sharing a tag.

Supports integer indexing (including negative), len(), and iteration. When exactly one element is present, calling or str()-ing the sequence delegates to that sole item.

__bool__()

True if self else False

__call__(*args, **kwargs)

Call self as a function.

__getitem__(key, /)

Return self[key].

__iter__()

Implement iter(self).

__len__()

Return len(self).

__str__()

Return str(self).


dictify

pygixml.dictify — XML to dict interface, compatible with xmltodict.

All logic lives in dictify.pxi, compiled into pygixml_cy.so.

Usage:

from pygixml import dictify

d = dictify.parse(xml_string)
s = dictify.unparse(d, pretty=True)
d = dictify.parse_file("data.xml")

# streaming: yield one dict per element without loading the whole document
for record in dictify.iterdict("big.xml", "record"):
    process(record)
pygixml.dictify.iterdict(source, tag, attr_prefix='@', cdata_key='#text', force_list=None, stack_size=4096, chunk_size=65536)

Stream-parse XML and yield each matching element as a plain dict, one at a time.

Identical to iterjsonl() except it yields StreamElement.to_dict() results instead of JSON strings – useful when you want to keep working with the data in Python rather than as text.

Example:

for record in dictify.iterdict("big.xml", "record"):
    print(record["name"], record["@id"])
pygixml.dictify.parse(xml, attr_prefix='@', cdata_key='#text', force_list=None, encoding=None)

Parse an XML string into an OrderedDict-compatible dict.

Matches the behaviour of the xmltodict library:

  • Attributes are stored with attr_prefix prepended (default "@").

  • Text content of mixed nodes is stored under cdata_key (default "#text").

  • Repeated sibling elements are automatically collapsed into a list.

  • Empty elements become None.

  • Whitespace-only text nodes become None.

Parameters:
  • xml (str) – XML source text.

  • attr_prefix (str) – Prefix for attribute keys. Default "@".

  • cdata_key (str) – Key for text content in mixed nodes. Default "#text".

  • force_list (set | True | None) – Tag names that should always be wrapped in a list even when only one element is present. Pass True to force all tags into lists.

  • encoding – Accepted for API compatibility; pygixml auto-detects encoding and this parameter is ignored.

Returns:

Parsed document as a nested dict.

Return type:

dict

Raises:

PygiXMLError – If the XML is malformed.

Example:

from pygixml import dictify
d = dictify.parse('<root id="1"><item>a</item><item>b</item></root>')
# {'root': {'@id': '1', 'item': ['a', 'b']}}
pygixml.dictify.parse_file(path, attr_prefix='@', cdata_key='#text', force_list=None)

Parse an XML file into a dict. Same semantics as dictify_parse().

Parameters:
  • path (str) – Path to the XML file.

  • attr_prefix (str) – Prefix for attribute keys. Default "@".

  • cdata_key (str) – Key for text content in mixed nodes.

  • force_list (set | True | None) – Tags to always wrap in a list.

Returns:

Parsed document as a nested dict.

Return type:

dict

Raises:

PygiXMLError – If the file cannot be read or XML is malformed.

pygixml.dictify.unparse(input_dict, output=None, encoding='utf-8', full_document='true', indent='\t', attr_prefix='@', cdata_key='#text', pretty=False)

Emit an XML string from a dict produced by dictify_parse().

Implemented entirely in C++ — no Python list, string concatenation, or f-string formatting during serialization. Only one Python str is created at the very end.

Matches the xmltodict.unparse signature.

Parameters:
  • input_dict (dict) – A {root_tag: value} dict.

  • output – Ignored (accepted for API compatibility).

  • encoding (str) – Encoding declared in the XML header. Default "utf-8".

  • full_document (str) – "true" to include the XML declaration.

  • indent (str) – Indentation string when pretty is True. Default "\t".

  • attr_prefix (str) – Prefix that identifies attribute keys. Default "@".

  • cdata_key (str) – Key for text content in mixed nodes. Default "#text".

  • pretty (bool) – Whether to indent output. Default False.

Returns:

XML string.

Return type:

str

Raises:

ValueError – If input_dict does not have exactly one root key.

Example:

from pygixml import dictify
d = {'root': {'@id': '1', 'item': ['a', 'b']}}
print(dictify.unparse(d, pretty=True))

jsonify

pygixml.jsonify — direct XML → JSON serialization.

All heavy lifting is done in C++ (jsonify.pxi compiled into pygixml_cy.so). No Python dict/list is allocated during traversal — only one str at the end (or, for the streaming entry point below, not even that).

Usage:

from pygixml import jsonify

# smart dispatcher — str or ObjectifiedElement or XMLNode
jsonify.dumps("<root/>")
jsonify.dumps(root.user_profile)          # ObjectifiedElement
jsonify.dumps(doc.root)                   # XMLNode

# typed entry points
jsonify.dumps_str("<root/>")
jsonify.dumps_file("data.xml")
jsonify.dumps_obj(root.user_profile)
jsonify.dumps_node(doc.root)

# options
jsonify.dumps(xml, pretty=True, indent="  ", encoding="utf-8")
jsonify.dumps(xml, attr_prefix="", cdata_key="text")
jsonify.dumps(xml, force_list={"item"})

# streaming, constant-memory conversion for gigantic files:
# pure C++ (yxml + hand-written JSON writer) — no pugixml DOM, no
# Python dict/list, no `json` module, anywhere in the call chain.

# -> JSON Lines / streaming: use jsonify.iterjsonl() (a generator) instead
#    of a file-based function — write the file yourself if you need one:
#        with open("out.jsonl", "w") as f:
#            for line in jsonify.iterjsonl("huge.xml", "record"):
#                f.write(line + "\n")

# -> a single standard, valid JSON document (same shape as dumps()),
#    using an in-place seek-and-patch trick to avoid buffering whole
#    subtrees just to know where array brackets go
jsonify.stream_dump("huge.xml", "huge.json")            # compact (default)
jsonify.stream_dump("huge.xml", "huge.json", indent=2)  # pretty, 2 spaces

# -> a .jsonl file, written straight from C++ (no per-element
#    Python object at all, unlike iterjsonl())
jsonify.stream_jsonl("huge.xml", "huge.jsonl", "record")
pygixml.jsonify.dumps(source, attr_prefix='@', cdata_key='#text', force_list=None, pretty=False, indent='\t', encoding='utf-8')

Serialize XML to JSON — smart dispatcher.

Routes automatically based on source type:

Note

File input is intentionally excluded from the dispatcher — use jsonify_dumps_file() explicitly for files.

Parameters:
  • source (str | pygixml.ObjectifiedElement | pygixml.XMLNode) – Input XML.

  • attr_prefix (str) – Prefix for attribute keys. Default "@".

  • cdata_key (str) – Key for text content. Default "#text".

  • force_list (set | True | None) – Tags always serialised as array.

  • pretty (bool) – Indent output. Default False.

  • indent (str) – Indentation string. Default "\t".

Returns:

JSON string.

Return type:

str

Raises:
  • PygiXMLError – If the XML is malformed.

  • TypeError – If source type is not recognised.

  • ValueError – If source is a str but does not look like XML.

Example:

from pygixml import jsonify, objectify

jsonify.dumps("<root id='1'><item>x</item></root>")
jsonify.dumps(root.user_profile)   # ObjectifiedElement
jsonify.dumps(doc.root)            # XMLNode
jsonify.dumps_file("data.xml")     # file — explicit
pygixml.jsonify.dumps_file(path, attr_prefix='@', cdata_key='#text', force_list=None, pretty=False, indent='\t', encoding='utf-8')

Serialize an XML file directly to JSON.

Parameters:

path (str) – Filesystem path to the XML file.

Returns:

JSON string.

Return type:

str

Raises:

PygiXMLError – If the file cannot be read or XML is malformed.

pygixml.jsonify.dumps_node(node, attr_prefix='@', cdata_key='#text', force_list=None, pretty=False, indent='\t', encoding='utf-8')

Serialize a low-level pygixml.XMLNode directly to JSON.

Parameters:

node (pygixml.XMLNode) – Node to serialise.

Returns:

JSON string.

Return type:

str

Raises:

TypeError – If node is not an XMLNode.

pygixml.jsonify.dumps_obj(elem, attr_prefix='@', cdata_key='#text', force_list=None, pretty=False, indent='\t', encoding='utf-8')

Serialize an pygixml.ObjectifiedElement subtree directly to JSON.

Parameters:

elem (pygixml.ObjectifiedElement) – Element to serialise.

Returns:

JSON string.

Return type:

str

Raises:

TypeError – If elem is not an ObjectifiedElement.

pygixml.jsonify.dumps_str(xml, attr_prefix='@', cdata_key='#text', force_list=None, pretty=False, indent='\t', encoding='utf-8')

Serialize an XML string directly to JSON.

Parameters:

xml (str) – XML source text.

Returns:

JSON string.

Return type:

str

Raises:

PygiXMLError – If the XML is malformed.

pygixml.jsonify.iterjsonl(source, tag, attr_prefix='@', cdata_key='#text', force_list=None, stack_size=4096, chunk_size=65536)

Stream-parse XML and yield each matching element as a JSON string, one at a time – a generator, not a file.

Built directly on iterfind() (the same tested, yxml-backed streaming parser used throughout this module) plus StreamElement.to_json(), which serializes one element straight to a str without ever constructing an intermediate dict and without using the json module. Each yielded string is exactly what json.dumps() would produce for that element’s StreamElement.to_dict() – but skips building the dict at all.

Memory use is bounded by one element’s subtree at a time (the same model as iterfind()/ElementTree’s iterparse – not the whole document), since each StreamElement is discarded once its JSON string has been produced and the generator moves on.

This is the right tool when you want JSON text in Python (to forward over a socket, push into a queue, write your own framing, etc.) without round-tripping through a file. If you actually want a .jsonl file on disk, see pygixml.jsonify.stream_jsonl() instead – that one stays in C++ all the way from the XML bytes to the file write, with no per-element Python object (no StreamElement, no dict, no str) ever created.

Parameters:
  • source (str | os.PathLike | bytes | bytearray | file-like) – Same as iterparse().

  • tag (str) – Tag name of the elements to convert and yield.

  • attr_prefix – Same meaning as StreamElement.to_json().

  • cdata_key – Same meaning as StreamElement.to_json().

  • force_list – Same meaning as StreamElement.to_json().

  • stack_size – Same meaning as iterparse().

  • chunk_size – Same meaning as iterparse().

Yields:

str – One JSON object string per matched element.

Examples

for line in jsonify.iterjsonl("big.xml", "record"):
    send_to_queue(line)     # already a JSON string

# writing a .jsonl file yourself, if you want one:
with open("out.jsonl", "w") as f:
    for line in jsonify.iterjsonl("big.xml", "record"):
        f.write(line)
        f.write("\n")
pygixml.jsonify.stream_dump(xml_path, json_path, attr_prefix='@', cdata_key='#text', force_list=None, indent=0, stack_size=4096, io_buf_size=65536)

Convert a (potentially gigantic) XML file to a single, standard, valid JSON document — in roughly constant memory.

Unlike stream_jsonl() (which writes JSON Lines — one independent object per line, by design, to sidestep the “do I need an array bracket” problem), this function produces exactly what dumps()/dumps_file() would produce: one JSON value (an object, mirroring the XML root) that round-trips through a normal json.load like any other JSON file. No pugixml DOM, no Python dict/list, and no json module are used internally — every byte is hand-emitted in C++, the same as stream_jsonl().

How it stays (mostly) constant-memory while still producing valid JSON syntax: a normal JSON array must know, before its closing ], whether more items follow. Instead of buffering whole subtrees to find out, this engine writes optimistically and patches the file in place once it learns more:

  • The first time a child tag is seen under some parent, a single placeholder byte is reserved right before its value and the tag is written as a plain (non-array) value.

  • If a second sibling with the same tag shows up, that one placeholder byte is overwritten with [ (an O(1) patch), and the new value is appended right after the first — this is the common case when same-tag siblings are adjacent in the XML, and it never needs to move any bytes around.

  • If XML interleaves a different child in between two same-tag siblings, the engine “splices”: it shifts just the bytes written in between forward (using a small fixed-size buffer, in chunks) to open a gap for the new sibling, then continues. This costs time proportional to how much was interleaved, not to the file size, and is the only case where any data movement happens at all.

Because of that splice fallback, worst-case time can exceed stream_jsonl()’s for documents where repeated sibling tags are heavily interleaved with unrelated children — for typical record-oriented XML (where <tag> repeats appear consecutively) this never triggers and the function runs at full streaming speed.

Parameters:
  • xml_path (str) – Path to the input XML file.

  • json_path (str) – Path to the output JSON file. Overwritten if it exists.

  • attr_prefix (str) – Prefix for XML attribute names in JSON keys. Default "@".

  • cdata_key (str) – JSON key used for an element’s text content when mixed with attributes or child elements. Default "#text".

  • force_list (set[str] | True | None) – Tag names that should always be serialised as a JSON array, even when only one sibling exists for a given parent. Pass True to force every child tag into an array. Default None (a tag becomes an array only when more than one sibling with that name actually appears under the same parent) — matching dumps()’s default behaviour.

  • indent (int) – Number of spaces to indent nested structures with, following the same convention as Python’s json.dump(..., indent=N). 0 (the default) produces compact output with no extra whitespace. Any positive value enables multi-line, indented output using that many spaces per nesting level.

  • stack_size (int) – Size in bytes of yxml’s internal name stack.

  • io_buf_size (int) – Bytes read per XML I/O operation. Default 65536 (64 KB).

Returns:

Number of XML elements processed (informational).

Return type:

int

Raises:

PygiXMLError – On malformed XML, or if the input/output file cannot be opened.

Examples

from pygixml import jsonify
jsonify.stream_dump("huge.xml", "huge.json")            # compact
jsonify.stream_dump("huge.xml", "huge.json", indent=2)  # pretty

import json
with open("huge.json") as f:
    data = json.load(f)   # a single, ordinary, valid JSON document
pygixml.jsonify.stream_jsonl(xml_path, jsonl_path, tag, attr_prefix='@', cdata_key='#text', force_list=None, stack_size=4096, io_buf_size=65536)

Stream-convert an XML file straight to a .jsonl file, one matched element per line – entirely in C++.

Unlike iterjsonl(), no StreamElement is ever built and no Python str/dict/list is created for the matched elements themselves: the XML bytes are read with the same yxml-based parser used throughout this module, each matched element’s JSON object is assembled in a small in-memory buffer (bounded by that one element’s own subtree, the same constant-memory model as iterfind()), and written straight to the .jsonl file – nothing crosses into Python until the function returns the count of records written.

This is the right tool when the destination really is a file on disk and you don’t need the records in Python at all (e.g. a one-shot batch conversion). If you want each record back as a Python str (to forward over a socket, filter, re-encode, etc.), use iterjsonl() instead.

Parameters:
  • xml_path (str) – Path to the source XML file.

  • jsonl_path (str) – Path to the .jsonl file to write (overwritten if it exists).

  • tag (str) – Tag name of the elements to convert and write, one per line.

  • attr_prefix – Same meaning as StreamElement.to_json().

  • cdata_key – Same meaning as StreamElement.to_json().

  • force_list – Same meaning as StreamElement.to_json().

  • stack_sizestack_size is yxml’s internal element/attribute name stack (same meaning as iterparse()’s stack_size); io_buf_size is the read chunk size from the XML file.

  • io_buf_sizestack_size is yxml’s internal element/attribute name stack (same meaning as iterparse()’s stack_size); io_buf_size is the read chunk size from the XML file.

Returns:

The number of matched elements written.

Return type:

int

Notes

If tag itself appears nested inside an already-matched element, that inner occurrence is folded in as an ordinary nested field of the outer match (under its own tag-name key) rather than being written as a second, separate line – only the outermost occurrence of a match starts a new JSONL record. This only matters for genuinely self-nested tags; a flat list of repeated sibling records (the common case) is unaffected.

Examples

from pygixml import jsonify
n = jsonify.stream_jsonl("big.xml", "big.jsonl", "record")
print(f"wrote {n} records")

Streaming

class pygixml.StreamElement

A small, ElementTree-like XML element produced while streaming.

StreamElement is a standalone, lightweight node – it is not connected to a pugixml document. Each instance has a tag, attrib dict, optional text/tail strings, and a list of child StreamElement nodes (accessible via iteration, indexing, len(), or children).

Call clear() once you’re done with an element (and its subtree) to free the memory it holds – the classic iterparse idiom for keeping peak memory low on huge documents.

__bool__()

True if self else False

__getitem__(key, /)

Return self[key].

__iter__()

Implement iter(self).

__len__()

Return len(self).

__repr__()

Return repr(self).

clear()

Drop this element’s attributes, text, tail and children, freeing the memory they hold (the element itself, e.g. as an already-appended child of its parent, is left in place).

find(path)

Return the first descendant matching path, or None. See findall() for the supported path syntax.

findall(path)

Find descendants matching path.

Supports "tag" / "a/b/c" (direct-child traversal), "*" (any child) and ".//tag" (any descendant). Returns a list, possibly empty.

findtext(path, default=None)

Return .text of the first match of path, or default.

get(key, default=None)

Return attrib.get(key, default).

items()

Return the (name, value) attribute pairs.

iter(tag=None)

Depth-first iterate this element and all its descendants, optionally restricted to a given tag ("*" or None matches everything).

keys()

Return the attribute names (a view over attrib).

to_dict(attr_prefix='@', cdata_key='#text', force_list=None)

Convert this element (and its subtree) to a plain dict, using the same convention as pygixml.jsonify.dumps():

  • Attributes become {attr_prefix + name: value} entries.

  • A child tag that appears more than once (or is listed in force_list, or force_list is True) becomes a list; otherwise its value is used directly (no list wrapping).

  • Text content is folded in as cdata_key when the element also has attributes or children; otherwise the element’s value is its text (a plain string), matching the scalar shortcut used elsewhere in pygixml’s JSON conversion.

  • An element with no attributes, no children, and no text becomes None.

This only ever builds dict/list/str — no JSON text is produced. See to_json() for a direct-to-string version that skips building this dict entirely.

to_json(attr_prefix='@', cdata_key='#text', force_list=None)

Serialize this element (and its subtree) directly to a JSON strwithout ever constructing an intermediate dict or list, and without using the json module. Uses the same conventions as to_dict()/jsonify.dumps().

This is the fast path for converting many elements one at a time (e.g. from pygixml.iterfind()) straight to JSON text, skipping the dict-building step entirely:

for elem in pygixml.iterfind("big.xml", "record"):
    line = elem.to_json()   # str, ready to write/yield
    ...
    elem.clear()
attrib
children

The list of direct child StreamElement nodes.

tag
tail
text
class pygixml.PullParser

An incremental (“push”) XML parser.

Feed it bytes as they become available via feed(), then drain completed ("start" | "end" | "pi", value) events with read_events(). Call close() once there is no more input.

This is the low-level engine behind iterparse(); use it directly when XML data arrives incrementally (e.g. from a socket or an async stream) rather than from a file you can simply read in chunks.

Parameters:
  • events – subset of ("start", "end", "pi") – which events read_events() produces. The element tree is always built regardless of events; this only controls what is yielded.

  • tag – if given, only elements whose tag equals tag produce "start"/"end" events (their subtrees are still built and linked into the document as usual).

  • stack_size – size in bytes of yxml’s internal name stack. Must be large enough to hold the names of all simultaneously-open elements/attributes/PIs plus their nesting depth (each name is stored with a trailing NUL). Increase this for documents with very deep nesting or very long tag/attribute names.

Example:

parser = pygixml.PullParser(events=("start", "end"))
for chunk in network_stream:
    parser.feed(chunk)
    for event, elem in parser.read_events():
        ...
parser.close()
for event, elem in parser.read_events():
    ...
close()

Signal end-of-input.

Validates that the document ended in a valid state (e.g. not mid-comment or with unclosed elements) and flushes any remaining buffered text. Safe to call multiple times.

feed(data)

Feed a chunk of well-formed, UTF-8 encoded XML bytes.

Completed events become available through read_events(). Raises PygiXMLError on malformed XML.

read_events()

Iterate over (event, value) pairs accumulated so far.

event is "start", "end" or "pi". For "start"/"end", value is a StreamElement (the same instance for both events of a given element). For "pi", value is a (target, content) tuple.

Draining this generator removes the events from the internal queue – each event is only produced once.

closed
line

Current 1-based line number – useful in error messages.

position

Total number of bytes consumed so far.