Note
This Python package makes it easier to work with EML_NL
files in Python, but is no substitute for the official standard. Please use the official XSD files for validating EML_NL
files.
Data bindings for the EML_NL Standard to load EML_NL files into Python dataclasses with correct structure, datatypes and typehints following the EML_NL Xml Schema Definitions. Type hints can be statically checked using mypy or pyright.
- At least Python version 3.10 for the KW_ONLY type annotations for dataclasses. This is so that non-nullable fields can be marked as mandatory (refer to xsdata documentation).
- xsData for parsing using these data bindings.
For running tests, additionally:
- pytest for the test framework.
- formencode for XML comparison.
The bindings are tested on over 2500 different EML files from different type of Dutch elections, all downloaded from data.overheid.nl using a roundtrip serialization test. To run the tests, install the test dependencies (see above), put EML files into a data
folder and run pytest
in the root folder.
Additionally, the bindings are tested against the election data specified in testfiles.txt
. Due to the test duration, only the most recent election files are included in this test.
Make sure that xsData is installed. Using example file Telling_PS2023_Flevoland_gemeente_Almere.eml.xml
which has EML id 510b:
from pathlib import Path
from xsdata.formats.dataclass.parsers import XmlParser
from xsdata.formats.dataclass.serializers import XmlSerializer
from xsdata.formats.dataclass.serializers.config import SerializerConfig
from pyeml_bindings import Eml510
from pyeml_bindings.namespace import NAMESPACE
# Create a parser object, can optionally be given extra config, see xsData docs
parser = XmlParser()
# Parse the eml file, specifying the dataclass to parse to.
eml = parser.from_path(Path("Telling_PS2023_Flevoland_gemeente_Almere.eml.xml"), Eml510)
# We can now access the data using standard Python syntax
# prints "Provinciale Staten Flevoland 2023"
print(eml.count.election.election_identifier.election_name)
# Or change some of the fields
eml.count.election.contests.contest[0].total_votes.cast = 1234
# And write back to EML using a serializer
serializer = XmlSerializer(config=SerializerConfig(xml_declaration=False))
with open(Path("output.xml"), "w") as out_file:
# We can optionally pass the NAMESPACE from the bindings to the write function
# to use the same namespace prefixes.
# If we don't, we still get back valid EML but with ns0, ns1 etc.
serializer.write(out=out_file, obj=eml, ns_map=NAMESPACE)
To build the package yourself instead of installing the .whl
, simply clone the repository and then in the root folder run.
python -m build
or you can simply install the package by running
python -m pip install .
These bindings are mostly generated using xsData with some minor changes where needed. See commit history for these changes.