Work with PROV-XML

PROV-XML support needs the optional lxml dependency:

python -m pip install "prov[xml]"

Serialize to a file

import prov.model as pm

document = pm.ProvDocument()
document.set_default_namespace("http://example.org/")
document.entity("e1")

document.serialize("document.xml", format="xml")

Serialize to a string

xml_str = document.serialize(format="xml")
print(xml_str)

Force xsd:type attributes

By default xsi:type is only written for prov:type, prov:location, and prov:value, matching the PROV-XML spec examples. Pass force_types=True to write it for every non-prov: attribute too:

xml_str_typed = document.serialize(format="xml", force_types=True)

Deserialize from a file or stream

loaded = pm.ProvDocument.deserialize("document.xml", format="xml")
assert loaded == document

Deserialize from a string

loaded = pm.ProvDocument.deserialize(content=xml_str, format="xml")

Auto-detect the format with prov.read()

prov.read() tries each registered deserializer in turn — PROV-JSON, then PROV-O/RDF, then PROV-N, then PROV-XML — treating any failure from a candidate as “not this format” and moving on to the next one, stopping at the first deserializer that both succeeds and produces a non-empty document. Valid PROV-XML therefore auto-detects, whether the source is a file path or raw content:

import prov

loaded = prov.read("document.xml")  # no format given
assert loaded == document

A seekable stream source (an open file object, io.StringIO, io.BytesIO, …) is rewound between auto-detection attempts, so it also auto-detects; a non-seekable stream is consumed by the first candidate, so pass format="xml" explicitly for those.

Passing format="xml" explicitly skips the trial-and-error and gives the real traceback if the content is not valid PROV-XML:

loaded = prov.read("document.xml", format="xml")
assert loaded == document

Common errors

Malformed XML raises lxml’s own syntax error, not a prov-specific exception:

try:
    pm.ProvDocument.deserialize(content="not xml", format="xml")
except Exception as e:
    print(f"{type(e).__name__}: {e}")
XMLSyntaxError: Start tag expected, '<' not found, line 1, column 1 (<string>, line 1)