pymaiml.serialization¶
serialization ¶
pymaiml.serialization¶
Converts maiml_domain object trees into real MaiML (JIS K 0200 / MaiML-Schema-1_0) XML text/files.
maiml_domain deliberately has no XML (de)serialization of its own -- see its README. This module is the "graduated" version of the throwaway converter that MaiML-Domain/tests/build_sample_maiml.py used to validate the domain model during development: the same recursive property/content handling, but now generalized (via pymaiml._xsi_registry) to cover every property/content type maiml_domain defines, and extended to cover every structural element (document/protocol/data/eventLog/pnml), not just the narrow slice one sample file happened to exercise.
Element ordering in every writer function below follows MaiML-Schema-1_0 directly (maiml.xsd / maiml-document.xsd / maiml-protocol.xsd / maiml-data.xsd / maiml-eventLog.xsd / maiml-pnml.xsd / maiml-core.xsd / maiml-property.xsd) -- see the docstring of each write* function for the specific xs:sequence it mirrors.
loads()/load() are the inverse: parse MaiML XML (via lxml, so attribute namespace maps are easy to inspect) back into a maiml_domain object tree, returned wrapped in a LoadedMaiml along with the root's own custom namespace declarations and every id encountered in the file -- both are needed by the "load an existing protocol, keep it, add new data/eventLog" workflow: the namespaces so dumps() can be given the same extra_namespaces= again, and the ids so pymaiml.builders.IdFactory.from_existing_ids() can avoid generating a new id that collides with one already in the file.
Known limitations (documented rather than silently guessed at):
- encrypted_data is stored (by maiml_domain) as a
raw extra_namespaces when
writing -- MaiML's key attributes are xs:QName, which XSD validation
rejects if the prefix has no xmlns declaration in scope. loads()
reports whatever was declared on the root element via
LoadedMaiml.namespaces so a load-modify-dump round trip can reuse it
without the caller having to re-track it by hand.
- document.signature (a
LoadedMaiml
dataclass
¶
LoadedMaiml(root: Union['m.MaimlRootType', 'm.ProtocolFileRootType'], namespaces: Dict[str, str] = dict(), ids: List[str] = list())
Result of loads()/load(): the parsed object tree plus the two things a "load an existing file, keep its protocol, add new data/eventLog" workflow needs and can't get from the maiml_domain objects alone.
root: a MaimlRootType or ProtocolFileRootType, matching the file's own
xsi:type. For a ProtocolFileRootType, build a new MaimlRootType
re-using root.document and root.protocol as-is, plus your own
new DataType/EventLogType, then dumps() that.
namespaces: every xmlns:
dumps ¶
dumps(root_obj: Union['m.MaimlRootType', 'm.ProtocolFileRootType'], *, extra_namespaces: Optional[Dict[str, str]] = None, pretty: bool = True) -> str
Serialize a MaimlRootType/ProtocolFileRootType object tree to a MaiML XML string.
extra_namespaces: {prefix: uri} declared as xmlns:
root_obj.document.signature (a
The reason is not merely "an edited file's signature is stale" -- it's
that dumps() cannot make ANY serialization of this object tree a safe
carrier of a pre-existing enveloped signature, changed or not. MaiML's
Practically: pymaiml.serialization.loads() still reads root_obj.document.signature back for inspection (e.g. to hand to an external verifier), but dumps()/dump() never write it back out. If you need a signed MaiML file, dump the content first, then sign the resulting bytes with a dedicated external tool -- treat "build/edit the MaiML content" and "sign the finished file" as two separate steps, in that order, never the other way around.
Corollary (see CONTRIBUTING.md's "XML Signature" section): once a MaiML file IS signed, never run its bytes through pretty-printing, comment stripping, whitespace collapsing, line-ending conversion (CRLF/LF -- watch for tools/git settings that silently do this), or any other reformatting when merely saving/copying it -- any of those changes the canonicalization result the signature was computed over, even though pymaiml itself never re-emits a Signature it did not just compute.
ソースコード位置: pymaiml/serialization.py
dump ¶
dump(root_obj: Union['m.MaimlRootType', 'm.ProtocolFileRootType'], path: Union[str, Path], **kwargs) -> None
Serialize root_obj and write it to path (parent directories created as needed).
ソースコード位置: pymaiml/serialization.py
loads ¶
loads(xml_text: Union[str, bytes]) -> LoadedMaiml
Parse MaiML XML text (or bytes) into a LoadedMaiml.
xml_text is treated as untrusted input -- it may be a local file's contents today, but this is also the entry point a future API/upload surface would call directly, without necessarily running it through pymaiml.validation.validate() first. Parsing therefore explicitly disables external entity resolution and network access (see pymaiml._xml_security.make_untrusted_input_parser()) rather than relying on lxml's current defaults.
The returned root's document.signature (when the input carried a
ソースコード位置: pymaiml/serialization.py
load ¶
load(path: Union[str, Path]) -> LoadedMaiml