pyxsd 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyxsd-1.0.0/.gitignore +44 -0
- pyxsd-1.0.0/CHANGELOG.md +319 -0
- pyxsd-1.0.0/LICENSE +29 -0
- pyxsd-1.0.0/PKG-INFO +156 -0
- pyxsd-1.0.0/README.md +128 -0
- pyxsd-1.0.0/docs/CNAME +1 -0
- pyxsd-1.0.0/docs/_static/.gitkeep +0 -0
- pyxsd-1.0.0/docs/_templates/.gitkeep +0 -0
- pyxsd-1.0.0/docs/api.md +79 -0
- pyxsd-1.0.0/docs/architecture.md +84 -0
- pyxsd-1.0.0/docs/binding.md +135 -0
- pyxsd-1.0.0/docs/cli.md +67 -0
- pyxsd-1.0.0/docs/comparison-xmlschema.md +109 -0
- pyxsd-1.0.0/docs/conf.py +60 -0
- pyxsd-1.0.0/docs/contributing.md +90 -0
- pyxsd-1.0.0/docs/data-model.md +110 -0
- pyxsd-1.0.0/docs/demo.md +104 -0
- pyxsd-1.0.0/docs/history/index.md +7 -0
- pyxsd-1.0.0/docs/history/origins.md +26 -0
- pyxsd-1.0.0/docs/index.md +43 -0
- pyxsd-1.0.0/docs/migration-1.0.md +343 -0
- pyxsd-1.0.0/docs/quickstart.md +114 -0
- pyxsd-1.0.0/docs/supported.md +190 -0
- pyxsd-1.0.0/docs/transforms/class.md +31 -0
- pyxsd-1.0.0/docs/transforms/index.md +15 -0
- pyxsd-1.0.0/docs/transforms/using.md +94 -0
- pyxsd-1.0.0/docs/transforms/writing.md +146 -0
- pyxsd-1.0.0/docs/validation.md +172 -0
- pyxsd-1.0.0/examples/README.md +45 -0
- pyxsd-1.0.0/examples/about_examples.md +79 -0
- pyxsd-1.0.0/examples/demo/.gitignore +5 -0
- pyxsd-1.0.0/examples/demo/CountElements.py +36 -0
- pyxsd-1.0.0/examples/demo/demo.py +57 -0
- pyxsd-1.0.0/examples/demo/instance.xml +16 -0
- pyxsd-1.0.0/examples/demo/schema.xsd +33 -0
- pyxsd-1.0.0/examples/docx/README.md +83 -0
- pyxsd-1.0.0/examples/docx/document.xml +180 -0
- pyxsd-1.0.0/examples/docx/download_schemas.py +117 -0
- pyxsd-1.0.0/examples/docx/expected.md +13 -0
- pyxsd-1.0.0/examples/docx/lax/README.md +51 -0
- pyxsd-1.0.0/examples/docx/lax/expected.md +6 -0
- pyxsd-1.0.0/examples/docx/lax/instance.xml +30 -0
- pyxsd-1.0.0/examples/docx/lax/schema.xsd +61 -0
- pyxsd-1.0.0/examples/docx/lax/to_markdown.py +72 -0
- pyxsd-1.0.0/examples/docx/to_markdown.py +231 -0
- pyxsd-1.0.0/examples/gpx/README.md +56 -0
- pyxsd-1.0.0/examples/gpx/download_schemas.py +85 -0
- pyxsd-1.0.0/examples/gpx/instance.xml +2217 -0
- pyxsd-1.0.0/examples/gpx/track_stats.py +129 -0
- pyxsd-1.0.0/examples/legacy/README.md +47 -0
- pyxsd-1.0.0/examples/legacy/atom.py +10 -0
- pyxsd-1.0.0/examples/legacy/bravais_lattice.py +10 -0
- pyxsd-1.0.0/examples/legacy/cell_sizer.py +118 -0
- pyxsd-1.0.0/examples/legacy/coord_viewer.py +27 -0
- pyxsd-1.0.0/examples/legacy/expand_cell.py +57 -0
- pyxsd-1.0.0/examples/legacy/format_for_visit.py +35 -0
- pyxsd-1.0.0/examples/legacy/sampleTransformFile.txt +3 -0
- pyxsd-1.0.0/examples/legacy/sphere_cutter.py +60 -0
- pyxsd-1.0.0/examples/legacy/vector.py +57 -0
- pyxsd-1.0.0/examples/musicxml/README.md +63 -0
- pyxsd-1.0.0/examples/musicxml/download_schemas.py +110 -0
- pyxsd-1.0.0/examples/musicxml/instance.xml +2131 -0
- pyxsd-1.0.0/examples/musicxml/note_stats.py +71 -0
- pyxsd-1.0.0/examples/transform_template_fromLibrary.py +25 -0
- pyxsd-1.0.0/examples/transform_template_fromTransform.py +32 -0
- pyxsd-1.0.0/examples/transform_template_library.py +21 -0
- pyxsd-1.0.0/pyproject.toml +152 -0
- pyxsd-1.0.0/src/pyxsd/__init__.py +74 -0
- pyxsd-1.0.0/src/pyxsd/__main__.py +6 -0
- pyxsd-1.0.0/src/pyxsd/alternatives.py +516 -0
- pyxsd-1.0.0/src/pyxsd/assertions.py +592 -0
- pyxsd-1.0.0/src/pyxsd/binding.py +104 -0
- pyxsd-1.0.0/src/pyxsd/cli.py +653 -0
- pyxsd-1.0.0/src/pyxsd/compositors.py +17 -0
- pyxsd-1.0.0/src/pyxsd/content_model.py +1205 -0
- pyxsd-1.0.0/src/pyxsd/derivation.py +356 -0
- pyxsd-1.0.0/src/pyxsd/dict_export.py +95 -0
- pyxsd-1.0.0/src/pyxsd/document.py +237 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/__init__.py +37 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/all.py +198 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/annotation.py +39 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/any.py +53 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/any_attribute.py +48 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/attribute.py +661 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/attribute_group.py +158 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/choice.py +70 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/complex_content.py +37 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/complex_type.py +543 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/documentation.py +58 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/element.py +759 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/element_representative.py +1658 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/enumeration.py +19 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/explicit_timezone.py +18 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/extension.py +86 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/fraction_digits.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/group.py +270 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/identity.py +532 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/length.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/list.py +122 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/max_exclusive.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/max_inclusive.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/max_length.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/min_exclusive.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/min_inclusive.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/min_length.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/notation.py +94 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/pattern.py +19 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/restriction.py +181 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/schema.py +133 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/sequence.py +47 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/simple_content.py +59 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/simple_type.py +79 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/total_digits.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/union.py +113 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/white_space.py +17 -0
- pyxsd-1.0.0/src/pyxsd/element_representatives/xsd_type.py +1255 -0
- pyxsd-1.0.0/src/pyxsd/exceptions.py +45 -0
- pyxsd-1.0.0/src/pyxsd/facets.py +1229 -0
- pyxsd-1.0.0/src/pyxsd/identity.py +1093 -0
- pyxsd-1.0.0/src/pyxsd/instance_binding.py +619 -0
- pyxsd-1.0.0/src/pyxsd/namespaces.py +194 -0
- pyxsd-1.0.0/src/pyxsd/nodes.py +39 -0
- pyxsd-1.0.0/src/pyxsd/open_content.py +706 -0
- pyxsd-1.0.0/src/pyxsd/particle_derivation.py +2007 -0
- pyxsd-1.0.0/src/pyxsd/regex_charset.py +176 -0
- pyxsd-1.0.0/src/pyxsd/schema.py +667 -0
- pyxsd-1.0.0/src/pyxsd/schema_base.py +2536 -0
- pyxsd-1.0.0/src/pyxsd/schema_checks.py +3528 -0
- pyxsd-1.0.0/src/pyxsd/schema_composition.py +1701 -0
- pyxsd-1.0.0/src/pyxsd/schema_context.py +160 -0
- pyxsd-1.0.0/src/pyxsd/schema_hints.py +164 -0
- pyxsd-1.0.0/src/pyxsd/transforms/__init__.py +18 -0
- pyxsd-1.0.0/src/pyxsd/transforms/displayer.py +40 -0
- pyxsd-1.0.0/src/pyxsd/transforms/print_data.py +27 -0
- pyxsd-1.0.0/src/pyxsd/transforms/to_dict.py +26 -0
- pyxsd-1.0.0/src/pyxsd/transforms/transform.py +215 -0
- pyxsd-1.0.0/src/pyxsd/tree.py +37 -0
- pyxsd-1.0.0/src/pyxsd/upa.py +322 -0
- pyxsd-1.0.0/src/pyxsd/validation.py +237 -0
- pyxsd-1.0.0/src/pyxsd/version_gates.py +103 -0
- pyxsd-1.0.0/src/pyxsd/versioning.py +268 -0
- pyxsd-1.0.0/src/pyxsd/wildcards.py +1120 -0
- pyxsd-1.0.0/src/pyxsd/writers/__init__.py +4 -0
- pyxsd-1.0.0/src/pyxsd/writers/xml_tag_writer.py +191 -0
- pyxsd-1.0.0/src/pyxsd/writers/xml_tree_writer.py +258 -0
- pyxsd-1.0.0/src/pyxsd/xpath_api.py +93 -0
- pyxsd-1.0.0/src/pyxsd/xpath_assertions.py +571 -0
- pyxsd-1.0.0/src/pyxsd/xpath_subset.py +227 -0
- pyxsd-1.0.0/src/pyxsd/xsd_data_types.py +1351 -0
- pyxsd-1.0.0/src/pyxsd/xsi.py +144 -0
- pyxsd-1.0.0/tests/conformance/cases.toml +9167 -0
- pyxsd-1.0.0/tests/conformance/unsupported.toml +65 -0
- pyxsd-1.0.0/tests/conformance_runner.py +169 -0
- pyxsd-1.0.0/tests/conftest.py +86 -0
- pyxsd-1.0.0/tests/fixtures/all/instance.xml +6 -0
- pyxsd-1.0.0/tests/fixtures/all/schema.xsd +12 -0
- pyxsd-1.0.0/tests/fixtures/choice/instance.xml +8 -0
- pyxsd-1.0.0/tests/fixtures/choice/schema.xsd +25 -0
- pyxsd-1.0.0/tests/fixtures/compose/common.xsd +15 -0
- pyxsd-1.0.0/tests/fixtures/compose/extra.xsd +8 -0
- pyxsd-1.0.0/tests/fixtures/compose/instance.xml +9 -0
- pyxsd-1.0.0/tests/fixtures/compose/redefined.xsd +9 -0
- pyxsd-1.0.0/tests/fixtures/compose/schema.xsd +28 -0
- pyxsd-1.0.0/tests/fixtures/datatypes/instance.xml +19 -0
- pyxsd-1.0.0/tests/fixtures/datatypes/schema.xsd +24 -0
- pyxsd-1.0.0/tests/fixtures/defaults/instance.xml +5 -0
- pyxsd-1.0.0/tests/fixtures/defaults/schema.xsd +16 -0
- pyxsd-1.0.0/tests/fixtures/groups/instance.xml +7 -0
- pyxsd-1.0.0/tests/fixtures/groups/schema.xsd +18 -0
- pyxsd-1.0.0/tests/fixtures/identity/instance.xml +11 -0
- pyxsd-1.0.0/tests/fixtures/identity/schema.xsd +43 -0
- pyxsd-1.0.0/tests/fixtures/inventory/instance.xml +16 -0
- pyxsd-1.0.0/tests/fixtures/inventory/schema.xsd +33 -0
- pyxsd-1.0.0/tests/fixtures/nested/instance.xml +15 -0
- pyxsd-1.0.0/tests/fixtures/nested/schema.xsd +29 -0
- pyxsd-1.0.0/tests/fixtures/nillable/instance.xml +5 -0
- pyxsd-1.0.0/tests/fixtures/nillable/schema.xsd +14 -0
- pyxsd-1.0.0/tests/fixtures/primitives/instance.xml +16 -0
- pyxsd-1.0.0/tests/fixtures/primitives/schema.xsd +20 -0
- pyxsd-1.0.0/tests/fixtures/substitution/instance.xml +6 -0
- pyxsd-1.0.0/tests/fixtures/substitution/schema.xsd +20 -0
- pyxsd-1.0.0/tests/fixtures/unions/instance.xml +6 -0
- pyxsd-1.0.0/tests/fixtures/unions/schema.xsd +23 -0
- pyxsd-1.0.0/tests/fixtures/wildcards/instance.xml +8 -0
- pyxsd-1.0.0/tests/fixtures/wildcards/schema.xsd +11 -0
- pyxsd-1.0.0/tests/fixtures/xsi_type/instance.xml +10 -0
- pyxsd-1.0.0/tests/fixtures/xsi_type/schema.xsd +32 -0
- pyxsd-1.0.0/tests/report_conformance.py +141 -0
- pyxsd-1.0.0/tests/report_xsts.py +188 -0
- pyxsd-1.0.0/tests/test_architecture.py +140 -0
- pyxsd-1.0.0/tests/test_cli.py +617 -0
- pyxsd-1.0.0/tests/test_composition.py +1348 -0
- pyxsd-1.0.0/tests/test_conformance.py +27 -0
- pyxsd-1.0.0/tests/test_conformance_runner.py +68 -0
- pyxsd-1.0.0/tests/test_content_model.py +463 -0
- pyxsd-1.0.0/tests/test_content_models.py +2344 -0
- pyxsd-1.0.0/tests/test_crash_elimination.py +700 -0
- pyxsd-1.0.0/tests/test_datatypes_coverage.py +688 -0
- pyxsd-1.0.0/tests/test_declaration_inheritance.py +176 -0
- pyxsd-1.0.0/tests/test_dict_export.py +90 -0
- pyxsd-1.0.0/tests/test_docs_examples.py +49 -0
- pyxsd-1.0.0/tests/test_document_api.py +164 -0
- pyxsd-1.0.0/tests/test_example_applications.py +339 -0
- pyxsd-1.0.0/tests/test_examples_transforms.py +99 -0
- pyxsd-1.0.0/tests/test_facets.py +646 -0
- pyxsd-1.0.0/tests/test_form_defaults.py +108 -0
- pyxsd-1.0.0/tests/test_generated_classes.py +166 -0
- pyxsd-1.0.0/tests/test_group_occurrences.py +107 -0
- pyxsd-1.0.0/tests/test_identity.py +1784 -0
- pyxsd-1.0.0/tests/test_identity_internals.py +541 -0
- pyxsd-1.0.0/tests/test_metamorphic.py +191 -0
- pyxsd-1.0.0/tests/test_misc_coverage.py +1141 -0
- pyxsd-1.0.0/tests/test_name_collision.py +143 -0
- pyxsd-1.0.0/tests/test_namespaces.py +1301 -0
- pyxsd-1.0.0/tests/test_nil_semantics.py +266 -0
- pyxsd-1.0.0/tests/test_nodes.py +19 -0
- pyxsd-1.0.0/tests/test_occurrence_values.py +803 -0
- pyxsd-1.0.0/tests/test_oracle.py +238 -0
- pyxsd-1.0.0/tests/test_parse_modes.py +217 -0
- pyxsd-1.0.0/tests/test_particle_binding.py +129 -0
- pyxsd-1.0.0/tests/test_particle_derivation.py +2792 -0
- pyxsd-1.0.0/tests/test_real_schema_support.py +128 -0
- pyxsd-1.0.0/tests/test_regex_charset.py +365 -0
- pyxsd-1.0.0/tests/test_release_gate.py +561 -0
- pyxsd-1.0.0/tests/test_round_trip.py +108 -0
- pyxsd-1.0.0/tests/test_schema_api.py +109 -0
- pyxsd-1.0.0/tests/test_schema_context.py +210 -0
- pyxsd-1.0.0/tests/test_schema_legality.py +3554 -0
- pyxsd-1.0.0/tests/test_send_tree_observability.py +59 -0
- pyxsd-1.0.0/tests/test_structural_schema.py +322 -0
- pyxsd-1.0.0/tests/test_substitution_groups.py +236 -0
- pyxsd-1.0.0/tests/test_transform_framework.py +246 -0
- pyxsd-1.0.0/tests/test_type_lattice_integration.py +136 -0
- pyxsd-1.0.0/tests/test_type_resolution.py +504 -0
- pyxsd-1.0.0/tests/test_upa.py +319 -0
- pyxsd-1.0.0/tests/test_upa_internals.py +70 -0
- pyxsd-1.0.0/tests/test_validation.py +358 -0
- pyxsd-1.0.0/tests/test_version_gates.py +83 -0
- pyxsd-1.0.0/tests/test_versioning.py +59 -0
- pyxsd-1.0.0/tests/test_wildcard_associations.py +215 -0
- pyxsd-1.0.0/tests/test_wildcard_attributes.py +895 -0
- pyxsd-1.0.0/tests/test_wildcard_particles.py +401 -0
- pyxsd-1.0.0/tests/test_wildcards_11.py +1333 -0
- pyxsd-1.0.0/tests/test_wildcards_algebra.py +132 -0
- pyxsd-1.0.0/tests/test_write_through.py +99 -0
- pyxsd-1.0.0/tests/test_writer_cli_edges.py +80 -0
- pyxsd-1.0.0/tests/test_writer_escaping.py +136 -0
- pyxsd-1.0.0/tests/test_xpath_api.py +85 -0
- pyxsd-1.0.0/tests/test_xsd11_coverage.py +977 -0
- pyxsd-1.0.0/tests/test_xsd11_features.py +1679 -0
- pyxsd-1.0.0/tests/test_xsd_data_types.py +819 -0
- pyxsd-1.0.0/tests/test_xsts_catalog.py +153 -0
- pyxsd-1.0.0/tests/test_xsts_outcomes.py +90 -0
- pyxsd-1.0.0/tests/test_xsts_runner.py +625 -0
- pyxsd-1.0.0/tests/test_xsts_selection.py +87 -0
- pyxsd-1.0.0/tests/test_xsts_suite.py +58 -0
- pyxsd-1.0.0/tests/xsts/README.md +134 -0
- pyxsd-1.0.0/tests/xsts/__init__.py +16 -0
- pyxsd-1.0.0/tests/xsts/baseline-xsd10.toml +41740 -0
- pyxsd-1.0.0/tests/xsts/baseline-xsd11.toml +83475 -0
- pyxsd-1.0.0/tests/xsts/baseline.py +150 -0
- pyxsd-1.0.0/tests/xsts/catalog.py +360 -0
- pyxsd-1.0.0/tests/xsts/drivers.py +576 -0
- pyxsd-1.0.0/tests/xsts/outcomes.py +91 -0
- pyxsd-1.0.0/tests/xsts/report.py +150 -0
- pyxsd-1.0.0/tests/xsts/runner.py +458 -0
- pyxsd-1.0.0/tests/xsts/selection.py +123 -0
pyxsd-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Python build artifacts
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
|
|
13
|
+
# Tooling caches
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
.coverage.*
|
|
19
|
+
htmlcov/
|
|
20
|
+
coverage.xml
|
|
21
|
+
|
|
22
|
+
# Local agent / code-index tooling
|
|
23
|
+
.codegraph/
|
|
24
|
+
.serena/
|
|
25
|
+
|
|
26
|
+
# Local design notes and agent plans (not part of the published project)
|
|
27
|
+
docs/superpowers/
|
|
28
|
+
|
|
29
|
+
# Docs build output
|
|
30
|
+
docs/_build/
|
|
31
|
+
|
|
32
|
+
# Downloaded schemas for the docx, gpx, and musicxml examples
|
|
33
|
+
# (fetch with examples/*/download_schemas.py; too large to commit)
|
|
34
|
+
examples/docx/schemas/
|
|
35
|
+
examples/gpx/schemas/
|
|
36
|
+
examples/musicxml/schemas/
|
|
37
|
+
|
|
38
|
+
# CLI transform output written next to the input file (the default
|
|
39
|
+
# -d/--directoryTransformed and -p/--parsedOutput filenames)
|
|
40
|
+
*Transformed.xml
|
|
41
|
+
*Parsed.xml
|
|
42
|
+
|
|
43
|
+
# OS noise
|
|
44
|
+
.DS_Store
|
pyxsd-1.0.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to pyxsd are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
For a narrative explanation of what changed between 0.1 and 1.0 — including a
|
|
9
|
+
complete breaking-changes table and step-by-step upgrade instructions — see the
|
|
10
|
+
[migration guide](https://pyxsd.knorby.com/migration-1.0.html).
|
|
11
|
+
|
|
12
|
+
## [1.0.0] - 2026-09-22
|
|
13
|
+
|
|
14
|
+
pyxsd 1.0.0 is a ground-up modernization of the 2006 0.1 release. The library
|
|
15
|
+
was ported from Python 2.3 to Python 3.11+, reorganized into a `src/` layout,
|
|
16
|
+
rewritten with modern Python idioms, extended to cover substantially more of
|
|
17
|
+
XSD 1.0, and placed under a comprehensive test and conformance suite. It also
|
|
18
|
+
carries a full validation-correctness pass, opt-in XML Namespaces support with
|
|
19
|
+
binding/parse modes, and three real-world examples validated against their
|
|
20
|
+
official schemas.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- The public object model: a compiled schema is a `pyxsd.Schema`
|
|
25
|
+
(`Schema.compile(xsd, mode=..., namespace_schemas=..., overlay=...)`),
|
|
26
|
+
and each `schema.parse(xml)` binds one instance document into a
|
|
27
|
+
`pyxsd.Document` carrying the merged `ValidationReport`
|
|
28
|
+
(`document.report`), `is_valid`, `require_valid()`, `transform(fn)`,
|
|
29
|
+
`revalidate()`, `walk()`, `write(dest)`, and `to_string()`. One
|
|
30
|
+
compiled schema can serve any number of documents. The one-call
|
|
31
|
+
shortcuts `pyxsd.parse(xml, xsd=...)` and `pyxsd.compile(xsd)` resolve
|
|
32
|
+
schema hints from the instance exactly like the CLI. The schema's own
|
|
33
|
+
findings are available at `schema.report` before any instance is
|
|
34
|
+
parsed.
|
|
35
|
+
- `pyxsd.ValidationError` (a `PyXSDError` subclass) raised by
|
|
36
|
+
`Schema.require_valid()` and `Document.require_valid()`; its `report`
|
|
37
|
+
attribute holds every issue that failed the check.
|
|
38
|
+
- Transforms are callables in the library: `document.transform(fn)`
|
|
39
|
+
applies any callable taking the tree root; one returning a tree root
|
|
40
|
+
comes back as a new `Document` against the same schema, while an
|
|
41
|
+
in-place transform returning `None` leaves the document unchanged. A
|
|
42
|
+
returned document shares the pre-transform report;
|
|
43
|
+
`document.revalidate()` re-parses the serialized tree for a report
|
|
44
|
+
that reflects its current shape. `document.walk()` yields every node
|
|
45
|
+
pre-order. On the command line the `-t 'Name(args)'` /
|
|
46
|
+
`-T file` call-string syntax is unchanged.
|
|
47
|
+
- Full XSD 1.0 built-in type lattice: all 45 built-in datatypes (derivation
|
|
48
|
+
families, temporal types, binary types, list types) with lexical validation.
|
|
49
|
+
- Facet enforcement for user-defined simpleTypes: `enumeration`, `pattern`,
|
|
50
|
+
`length`, `minLength`, `maxLength`, `minInclusive`, `minExclusive`,
|
|
51
|
+
`maxInclusive`, `maxExclusive`, `totalDigits`, `fractionDigits`, and
|
|
52
|
+
`whiteSpace`. Restriction chains follow the XSD merge rules (patterns
|
|
53
|
+
conjunct, enumerations intersect, bounds tighten); list types count items
|
|
54
|
+
for the length family; enumeration and bounds compare XSD values rather
|
|
55
|
+
than spellings; `whiteSpace` is applied before other facets. Facet
|
|
56
|
+
applicability, facet-value validity, and pattern syntax are reported as
|
|
57
|
+
schema-compilation errors. `pattern` uses the XSD 1.1 dialect through the
|
|
58
|
+
new `elementpath` dependency (minimal, pure-Python, no compiled
|
|
59
|
+
extensions), and expands the XML 1.1 `\i`/`\c` name-character classes
|
|
60
|
+
including astral characters.
|
|
61
|
+
- `BindingPolicy.facets` (`"strict"` by default, `"off"` restores
|
|
62
|
+
parsing-only behavior for data-mapping users).
|
|
63
|
+
- Facet enforcement reaches values bound through `simpleContent` complex
|
|
64
|
+
types (inline and direct restrictions, and extensions), applies element
|
|
65
|
+
`default`/`fixed` there, and fixes the crash when a `simpleContent`
|
|
66
|
+
extension's base is a primitive such as `xs:int`.
|
|
67
|
+
- Value-space comparison for temporal datatypes preserves fractional
|
|
68
|
+
seconds, distinguishes zoned from unzoned spellings while treating
|
|
69
|
+
different offsets of the same instant as equal, normalizes `24:00:00`,
|
|
70
|
+
and accepts year `0000` (XSD 1.1). Enumeration, bounds, and fixed-value
|
|
71
|
+
checks use the corrected values.
|
|
72
|
+
- `+INF` is accepted as a lexical form of `xs:float` and `xs:double`
|
|
73
|
+
(XSD 1.1).
|
|
74
|
+
- Structural schema elements: `xs:all`, `xs:union` (including inline member
|
|
75
|
+
types), `xs:group` with references (with cycle detection), attribute group
|
|
76
|
+
references, and permissive `xs:any` / `xs:anyAttribute` pass-through.
|
|
77
|
+
- Instance semantics: `minOccurs`/`maxOccurs` enforcement, nillable elements
|
|
78
|
+
with `xsi:nil`, `default`/`fixed` for elements and attributes (with forced
|
|
79
|
+
values), prohibited attributes, `xsi:type` dispatch on elements and roots,
|
|
80
|
+
`abstract` elements and types, `block` on substitution heads, and substitution
|
|
81
|
+
groups.
|
|
82
|
+
- Schema composition: `xs:include` (including chameleon schemas), `xs:import`,
|
|
83
|
+
and `xs:redefine` with cycle and namespace checks.
|
|
84
|
+
- Identity constraints: `xs:key`, `xs:unique`, and `xs:keyref` with an XPath
|
|
85
|
+
subset (`child`, `@attr`, `./step`, `.//descendant` steps), applied as a
|
|
86
|
+
post-parse validation pass.
|
|
87
|
+
- `ValidationReport` — errors and warnings collected as structured
|
|
88
|
+
`ValidationIssue` records with stable issue codes instead of printed
|
|
89
|
+
messages. Each document reports at `document.report` (the schema's
|
|
90
|
+
own findings at `schema.report`); CLI users get the rendered report
|
|
91
|
+
on stderr and `--strict`.
|
|
92
|
+
- `XMLNode` runtime-checkable Protocol describing the instance-tree shape
|
|
93
|
+
(`_name_`, `_attribs_`, `_children_`, `_value_`).
|
|
94
|
+
- Element and attribute descriptors support `__set_name__`, class-level
|
|
95
|
+
access, and working programmatic assignment.
|
|
96
|
+
- Over 1,000 tests, including a 93-case independently authored, suite-inspired
|
|
97
|
+
conformance corpus with a standalone pass-rate reporter
|
|
98
|
+
(`tests/report_conformance.py`), plus a cross-check against the
|
|
99
|
+
independent `xmlschema` library.
|
|
100
|
+
- Full type annotations; mypy runs in CI.
|
|
101
|
+
- Sphinx documentation site (MyST + furo) with quickstart, CLI reference,
|
|
102
|
+
architecture notes, transform authoring guide, binding/parse modes,
|
|
103
|
+
migration guide, and API reference; published at
|
|
104
|
+
<https://pyxsd.knorby.com/>.
|
|
105
|
+
- Runnable end-to-end demo in `examples/demo/` (CLI and library styles) and
|
|
106
|
+
a working custom-transform example.
|
|
107
|
+
- Real-world examples (`examples/musicxml/`, `examples/gpx/`,
|
|
108
|
+
`examples/docx/`) that validate genuine documents against their official
|
|
109
|
+
published schemas, fetched on demand by a local `download_schemas.py` (not
|
|
110
|
+
committed; the tests skip when absent). `musicxml` validates a public-domain
|
|
111
|
+
Bach chorale against the MusicXML 4.0 schema (which imports the XML and XLink
|
|
112
|
+
namespaces); `gpx` validates a real ride against the official GPX 1.1 schema,
|
|
113
|
+
including Garmin extension data admitted by `xs:any processContents="lax"`;
|
|
114
|
+
`docx` validates a realistic `word/document.xml` against the full ECMA-376
|
|
115
|
+
`wml.xsd` and renders style-aware Markdown covering multilevel lists, tables,
|
|
116
|
+
hyperlinks, breaks/tabs, run properties, and `xml:space="preserve"`. All
|
|
117
|
+
three run in `ParseModes.NAMESPACED`; the earlier no-namespace `ParseModes.LAX`
|
|
118
|
+
docx demo is kept under `examples/docx/lax/`.
|
|
119
|
+
- PyPI publishing via a tag-driven release workflow with OIDC trusted
|
|
120
|
+
publishing.
|
|
121
|
+
- `pyxsd.derivation`: XSD type-derivation compatibility used by `xsi:type`
|
|
122
|
+
dispatch, honoring element/type `block` (`#all`, `extension`, `restriction`).
|
|
123
|
+
- `unexpected-element` and `circular-attributeGroup` validation codes.
|
|
124
|
+
- `ValidationIssue.phase` (`"schema"` or `"instance"`) and
|
|
125
|
+
`ValidationReport.for_phase()`, so schema-compilation diagnostics can no
|
|
126
|
+
longer be confused with instance diagnostics.
|
|
127
|
+
- Manifest `expected_values` assertions in the conformance corpus (defaults
|
|
128
|
+
and folds are checked by value, not just by a clean report).
|
|
129
|
+
- `tests/test_oracle.py` cross-check against the independent `xmlschema`
|
|
130
|
+
library (dev dependency; a required CI job, env-gated locally by
|
|
131
|
+
`PYXSD_RUN_ORACLE=1`).
|
|
132
|
+
- `ParseModes` presets (`STRICT`, `LAX`, `NAMESPACED`) and the
|
|
133
|
+
`BindingPolicy` dataclass, plus `Schema.compile(..., mode=...)` and CLI
|
|
134
|
+
`--mode strict|lax` / `--namespaces strict|legacy`. Modes change only what
|
|
135
|
+
is bound into the tree; the validation report stays strict. See
|
|
136
|
+
`docs/binding.md`.
|
|
137
|
+
- Opt-in XML Namespaces support (`BindingPolicy.namespaces`, default
|
|
138
|
+
`legacy`): namespace capture during parsing, expanded-name component
|
|
139
|
+
identity, `elementFormDefault` / `attributeFormDefault`-aware instance
|
|
140
|
+
matching, prefixed `type`/`ref`/`xsi:type` resolution, cross-namespace
|
|
141
|
+
`xs:import` (including `Schema.compile(namespace_schemas=...)`),
|
|
142
|
+
wildcard
|
|
143
|
+
namespace lists and `processContents`, QName value-space identity, and
|
|
144
|
+
namespace-aware output writers.
|
|
145
|
+
- Validation codes `unknown-namespace-prefix`, `wildcard-no-declaration`,
|
|
146
|
+
and `import-unresolved` (namespaced mode).
|
|
147
|
+
- A `namespaces/` category in the conformance corpus (form defaults,
|
|
148
|
+
cross-namespace type/ref, `xsi:type`, wildcards, QName identity), run in
|
|
149
|
+
namespaced mode through both the gating suite and the `xmlschema` oracle.
|
|
150
|
+
- `Schema.compile` accepts `xsd_version` (`"1.0"` or `"1.1"`, default
|
|
151
|
+
`"1.1"`), exposed as `Schema.xsd_version`; the CLI gains
|
|
152
|
+
`--xsd-version {1.0,1.1}`. This is the declared version `vc:*`
|
|
153
|
+
conditional-inclusion selectors test against, so a schema compiled as
|
|
154
|
+
1.0 drops a declaration carrying `vc:minVersion="1.1"` (XSD 1.1 §4.2.2).
|
|
155
|
+
- XSD 1.0 mode reports XSD 1.1-only vocabulary with `xsd11-construct`
|
|
156
|
+
issues: the `assert`/`assertion`/`alternative`/`openContent`/`override`
|
|
157
|
+
elements, the 1.1-only attributes (`notNamespace`, `notQName`,
|
|
158
|
+
`defaultAttributes`, `defaultAttributesApply`, `inheritable`,
|
|
159
|
+
`xpathDefaultNamespace`), and references to 1.1 built-in types
|
|
160
|
+
(`dateTimeStamp`, `dayTimeDuration`, `yearMonthDuration`,
|
|
161
|
+
`anyAtomicType`, `precisionDecimal`).
|
|
162
|
+
- XSD 1.0 mode enforces three 1.0/1.1 semantic differences: the 1.0
|
|
163
|
+
`xs:all` 0..1 child-occurrence cap (`all-rule`), the 1.0 requirement
|
|
164
|
+
that a union declare at least one member type (`declaration-child`), and
|
|
165
|
+
the 1.1-only prohibition on `use="prohibited"` with `fixed`.
|
|
166
|
+
- `Document.to_dict()` / `Document.to_json()` export the bound tree as
|
|
167
|
+
plain Python data (attributes under `@`, text under `$`, repeated
|
|
168
|
+
children as lists), with a lexical-text mode and an `always_list`
|
|
169
|
+
option. The shipped `ToDict` transform exposes the codec to
|
|
170
|
+
`Document.transform` and to the CLI, which renders a dict result as
|
|
171
|
+
JSON.
|
|
172
|
+
- `Document.xpath()` evaluates an XPath expression over the bound tree
|
|
173
|
+
and returns the original bound nodes (scalars pass through);
|
|
174
|
+
`Document.find()`/`findall()` accept ElementTree's path subset. Both
|
|
175
|
+
support caller-supplied namespace prefixes and resolve to the same
|
|
176
|
+
bound objects the object model uses.
|
|
177
|
+
|
|
178
|
+
### Changed
|
|
179
|
+
|
|
180
|
+
- Requires Python 3.11+ (was Python 2.3).
|
|
181
|
+
- Project metadata lives in `pyproject.toml` (hatchling build, src layout);
|
|
182
|
+
`setup.py` removed.
|
|
183
|
+
- Package code moved to `src/pyxsd/` with snake_case module names throughout
|
|
184
|
+
(`pyXSD.py` → `pyxsd/schema.py` + `pyxsd/document.py`,
|
|
185
|
+
`xsdDataTypes.py` → `xsd_data_types.py`,
|
|
186
|
+
etc.).
|
|
187
|
+
- Classes are generated with `types.new_class()`, class wiring runs through
|
|
188
|
+
`SchemaBase.__init_subclass__()`, and descriptors bind via `__set_name__`.
|
|
189
|
+
- CLI is flag-based (`pyxsd -i instance.xml -s schema.xsd`); transform calls
|
|
190
|
+
require parentheses (`-t 'PrintData()'`) and are parsed with `ast` instead
|
|
191
|
+
of `eval`; stdin is read directly (no temp file); output files are properly
|
|
192
|
+
flushed and closed; `--strict` exits 1 when validation errors are present.
|
|
193
|
+
- The pipeline no longer writes files the caller did not ask for; `_No_Output_`
|
|
194
|
+
semantics are consistent, and `stdout` output works.
|
|
195
|
+
- The built-in type classes report their names in true XSD spelling
|
|
196
|
+
(`base64Binary`, not `Base64Binary`) and register in a lookup table generated
|
|
197
|
+
from the classes themselves.
|
|
198
|
+
- Instances honor XSD value semantics more faithfully: empty simple content
|
|
199
|
+
reads as an empty string (not the literal string `'True'`), text is
|
|
200
|
+
whitespace-collapsed per token-derived datatypes, and the document order of
|
|
201
|
+
children is preserved.
|
|
202
|
+
- Compose include/redefine cycles are deduplicated and reported as a
|
|
203
|
+
`compose-cycle` warning rather than a fatal error.
|
|
204
|
+
- The conformance runner validates the schema and instance phases
|
|
205
|
+
independently, so an instance error can no longer mask a schema error.
|
|
206
|
+
- The `xsi_type` fixture and `xsi:type` corpus cases now use a genuinely
|
|
207
|
+
derived type (the previous schemas were not valid XSD).
|
|
208
|
+
- The conformance corpus is described as independently authored, suite-inspired
|
|
209
|
+
regression cases rather than copied W3C/NIST cases.
|
|
210
|
+
- The corpus now carries an optional `mode` field, and the `xmlschema`
|
|
211
|
+
oracle runs every case under its declared binding policy so namespace,
|
|
212
|
+
wildcard, and QName behavior is cross-checked rather than skipped.
|
|
213
|
+
- The crystallography transforms from 0.1 moved from `examples/transforms/`
|
|
214
|
+
to `examples/legacy/` (their schemas and data are no longer distributed).
|
|
215
|
+
- GitHub Actions are pinned to the latest majors and the Pages deploy steps
|
|
216
|
+
run only on the default branch, so pull requests build docs without
|
|
217
|
+
requiring Pages.
|
|
218
|
+
- Element assignment now coerces a plain Python value through the declared
|
|
219
|
+
datatype (as attribute assignment already did) and reports a bad lexical
|
|
220
|
+
value instead of raising `TypeError`; a datatype instance of the wrong
|
|
221
|
+
type or an arbitrary object still raises. This unifies the mutation
|
|
222
|
+
policy across elements and attributes.
|
|
223
|
+
- The W3C XML Schema Test Suite harness gained `--enforce` (exit `2` on a
|
|
224
|
+
baseline regression or a newly observed failure) and a dispatch-only
|
|
225
|
+
GitHub Actions workflow that caches the corpus and gates both the XSD 1.1
|
|
226
|
+
and XSD 1.0 profiles against their checked-in baselines.
|
|
227
|
+
|
|
228
|
+
### Removed
|
|
229
|
+
|
|
230
|
+
- The monolithic `PyXSD` pipeline class (and the `pyxsd.parser` module
|
|
231
|
+
behind it), which parsed, validated, wrote, and transformed inside one
|
|
232
|
+
constructor. Its roles are split across `Schema.compile`,
|
|
233
|
+
`Schema.parse`, and the returned `Document`; see the migration guide
|
|
234
|
+
for the call-by-call mapping. Breaking change.
|
|
235
|
+
- The `SendTreeToPyXSD` transform, which wrote the tree to a temporary
|
|
236
|
+
file and re-fed it through the pipeline;
|
|
237
|
+
`Document.revalidate()` does the same job in one call with no
|
|
238
|
+
temporary files. Breaking change.
|
|
239
|
+
- The eight crystallography transforms (atom, vector, bravais lattice, cell
|
|
240
|
+
sizer, coordinate viewer, format for visit, sphere cutter) moved out of the
|
|
241
|
+
package to `examples/legacy/`; they are no longer installed with the
|
|
242
|
+
library. Breaking change — see the migration guide.
|
|
243
|
+
- epydoc-based `doc/` tree and dead pyxsd.org links replaced by the Sphinx
|
|
244
|
+
documentation site.
|
|
245
|
+
|
|
246
|
+
### Fixed
|
|
247
|
+
|
|
248
|
+
- Schema parsing could not even import on Python 3 (2015 formatting-tool
|
|
249
|
+
syntax error in `schemaBase.py`).
|
|
250
|
+
- Generated classes double-registered inline complexType children, producing
|
|
251
|
+
spurious "Order Error" reports.
|
|
252
|
+
- Element/attribute descriptor assignment silently discarded the assigned
|
|
253
|
+
value; it now stores and returns it correctly.
|
|
254
|
+
- Transform instances were appended via `collection.append[instance]`
|
|
255
|
+
(subscript instead of call) and transform output was written to the *input*
|
|
256
|
+
file name (data loss).
|
|
257
|
+
- `xmlFileOutput=True` crashed; boolean output now uses the default file name.
|
|
258
|
+
- Transform calls with `**kwargs` expansion produced garbage arguments and now
|
|
259
|
+
are rejected with a clear syntax error.
|
|
260
|
+
- Schema hints (`xsi:noNamespaceSchemaLocation`) resolved relative to the
|
|
261
|
+
current directory instead of the data file's directory.
|
|
262
|
+
- Written documents with `xsi:` attributes lost the `xmlns:xsi` declaration;
|
|
263
|
+
the writer now injects it so output reparses.
|
|
264
|
+
- Primitive-typed root elements crashed; they now parse, validate, and honor
|
|
265
|
+
`xsi:nil`.
|
|
266
|
+
- Built-in datatypes: XSD whitespace handling (replace/collapse, XML
|
|
267
|
+
whitespace only), IEEE binary32 semantics for `xs:float`, bounded timezones,
|
|
268
|
+
`24:00:00`, year `0000`/leading zeros, ASCII-only digits, base64 pad-bit
|
|
269
|
+
validation, list types requiring at least one item, explicit XML
|
|
270
|
+
NameStartChar/NameChar ranges, `anyURI` permitting spaces, and value-space
|
|
271
|
+
equality for `fixed` (hex case, list whitespace, equivalent timezones).
|
|
272
|
+
- Content models: a compiled particle tree now matches sequences, choices,
|
|
273
|
+
`all`, nested compositors, repeated groups, and substitutions with complete
|
|
274
|
+
consumption; unmatched and trailing children are reported instead of silently
|
|
275
|
+
dropped, and complex-content restrictions no longer retain removed particles.
|
|
276
|
+
- Elements whose declared type is a derived simple type are constructed as
|
|
277
|
+
values instead of crashing; primitive-typed roots share the child path's
|
|
278
|
+
empty/default/fixed/value validation and `xsi:nil` rules.
|
|
279
|
+
- Identity constraints: tables are scoped to each element occurrence, fields
|
|
280
|
+
compare XSD typed values (not lexical strings), multi-node fields and nilled
|
|
281
|
+
fields are handled, and constraints on primitive declarations are walked.
|
|
282
|
+
- Composition: each parser owns its component table (no cross-parser leakage;
|
|
283
|
+
an element and a type may share a name); element `ref`s inside groups resolve;
|
|
284
|
+
nested `attributeGroup` references merge; group/attributeGroup single-level
|
|
285
|
+
`redefine` rebinds inner references; namespace-only `xs:import` is allowed;
|
|
286
|
+
legal include cycles are deduplicated.
|
|
287
|
+
- `xsi:type` overrides must be validly derived from the declared type and are
|
|
288
|
+
rejected when blocked; substitution-group members use their own declaration's
|
|
289
|
+
`nillable`/`default`/`fixed`/identity constraints rather than the head's.
|
|
290
|
+
- `final` is treated as a whitespace-separated token list.
|
|
291
|
+
- `xs:attribute ref="..."` resolves across namespaces, including global
|
|
292
|
+
attributes declared in imported schemas; an unresolved reference reports
|
|
293
|
+
`unknown-attributeRef` and an unresolved type base reports `unknown-type`
|
|
294
|
+
instead of crashing during class construction.
|
|
295
|
+
- Unprefixed QName *values* (`type`, `base`, `ref`, `substitutionGroup`) use
|
|
296
|
+
the in-scope default namespace, as XSD requires (previously real OOXML
|
|
297
|
+
types such as `base="CT_Markup"` failed to resolve).
|
|
298
|
+
- `xml:space="preserve"` text keeps its significant leading/trailing and
|
|
299
|
+
repeated whitespace; string/simple-content values are no longer stripped.
|
|
300
|
+
- Content-model matching is memoized, so large real-world schemas such as
|
|
301
|
+
WordprocessingML no longer backtrack exponentially.
|
|
302
|
+
- Class generation iterates the parser-owned component table, so types that
|
|
303
|
+
share a local name across imported namespaces (for example `CT_Color`) no
|
|
304
|
+
longer shadow each other; type lookup resolves the QName before falling
|
|
305
|
+
back to the local name.
|
|
306
|
+
- A `ref` site resolves through its target declaration for instance matching,
|
|
307
|
+
so replacement attributes such as `r:id` and `xml:space` bind in the
|
|
308
|
+
referring element's namespace.
|
|
309
|
+
- Numerous other latent bugs found by the test suite and conformance corpus
|
|
310
|
+
(see the migration guide for the complete narrative).
|
|
311
|
+
- Assignment to an element or attribute descriptor now writes the value's
|
|
312
|
+
lexical form through to the serialized tree, so `doc.root.attr = value`
|
|
313
|
+
survives `to_string()`/`write()`/`revalidate()` (previously it was
|
|
314
|
+
validated but silently dropped from the output).
|
|
315
|
+
|
|
316
|
+
## [0.1] - 2006-09-11
|
|
317
|
+
|
|
318
|
+
Initial release: Python 2.3 prototype developed at Oak Ridge National
|
|
319
|
+
Laboratory for crystallography XML tooling. See `docs/history/` for origins.
|
pyxsd-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
This software was developed at Oak Ridge National Labatory, which is run
|
|
2
|
+
by UT Battelle for the U.S. Department of Energy. UT Battelle declined
|
|
3
|
+
to assert copyright, so the authors of the software hold the copyright.
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2006, Kali Norby and Michael Summers
|
|
6
|
+
All rights reserved.
|
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
|
8
|
+
modification, are permitted provided that the following conditions are met:
|
|
9
|
+
|
|
10
|
+
* Redistributions of source code must retain the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer.
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
13
|
+
notice, this list of conditions and the following disclaimer in the
|
|
14
|
+
documentation and/or other materials provided with the distribution.
|
|
15
|
+
* Neither the names of the Authors, Oak Ridge National Labatory, UT Battelle,
|
|
16
|
+
U.S. Department of Energy, nor the names of its contributors may be
|
|
17
|
+
used to endorse or promote products derived from this software without
|
|
18
|
+
specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
|
|
21
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
22
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
|
24
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
25
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
26
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
27
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
28
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
29
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
pyxsd-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pyxsd
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Schema-guided XML-to-Python object mapping with a transform pipeline
|
|
5
|
+
Project-URL: Homepage, https://github.com/knorby/pyxsd
|
|
6
|
+
Project-URL: Repository, https://github.com/knorby/pyxsd
|
|
7
|
+
Project-URL: Documentation, https://pyxsd.knorby.com/
|
|
8
|
+
Project-URL: Issues, https://github.com/knorby/pyxsd/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/knorby/pyxsd/blob/develop/CHANGELOG.md
|
|
10
|
+
Author-email: Kali Norby <kali.norby@gmail.com>
|
|
11
|
+
Maintainer-email: Kali Norby <kali.norby@gmail.com>
|
|
12
|
+
License-Expression: BSD-3-Clause
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: parser,schema,transform,validation,xml,xsd
|
|
15
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: elementpath<6,>=4.7
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# pyxsd
|
|
30
|
+
|
|
31
|
+
[](https://github.com/knorby/pyxsd/actions/workflows/ci.yml)
|
|
32
|
+
[](https://github.com/knorby/pyxsd/actions/workflows/docs.yml)
|
|
33
|
+
[](https://pypi.org/project/pyxsd/)
|
|
34
|
+
[](https://pypi.org/project/pyxsd/)
|
|
35
|
+
[](https://pyxsd.knorby.com/)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
|
|
38
|
+
**pyxsd** maps XML documents into Python object trees according to an XML
|
|
39
|
+
Schema (XSD), reports non-fatal validation issues, runs user-defined
|
|
40
|
+
*transforms*, and writes the tree back out as XML.
|
|
41
|
+
|
|
42
|
+
- **Minimal dependencies** — one small, pure-Python package (`elementpath`)
|
|
43
|
+
for XSD regular expressions and XPath queries; no compiled extensions
|
|
44
|
+
- **Schema-compiled classes** — your schema becomes real Python classes;
|
|
45
|
+
`xs:extension` becomes real subclassing
|
|
46
|
+
- **XSD 1.1 processor** — with an optional XSD 1.0 mode
|
|
47
|
+
(`Schema.compile(xsd, xsd_version="1.0")` / `--xsd-version 1.0`) that
|
|
48
|
+
applies the 1.0 vocabulary gate and semantic differences
|
|
49
|
+
- **Lax validation** — bad documents still build a tree; every issue is a
|
|
50
|
+
code-tagged entry in a `ValidationReport` (`--strict` and
|
|
51
|
+
`require_valid()` make it a CI failure)
|
|
52
|
+
- **Query and export** — `Document.xpath` / `find` / `findall` return the
|
|
53
|
+
original bound nodes, and `Document.to_dict` / `to_json` export plain
|
|
54
|
+
Python data (also as the `ToDict` transform)
|
|
55
|
+
- **Transform pipeline** — apply plain callables or `Transform` classes to
|
|
56
|
+
the bound tree (`document.transform(fn)`); chain them on the CLI
|
|
57
|
+
(`PrintData() > PrintData()`)
|
|
58
|
+
- A niche-but-real niche: runtime XML↔Python binding *plus* a transform
|
|
59
|
+
framework, without pulling in `lxml` or generating static code
|
|
60
|
+
|
|
61
|
+
## Quickstart
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install pyxsd
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Validate and parse from the command line:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# schema is located from the instance's schemaLocation hints
|
|
71
|
+
pyxsd -i inventory.xml --strict
|
|
72
|
+
|
|
73
|
+
# write the parsed tree and apply a transform
|
|
74
|
+
pyxsd -i inventory.xml -k -o parsed.xml -t 'PrintData()'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Or as a library:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import pyxsd
|
|
81
|
+
|
|
82
|
+
schema = pyxsd.Schema.compile("inventory.xsd")
|
|
83
|
+
schema.require_valid()
|
|
84
|
+
|
|
85
|
+
document = schema.parse("inventory.xml")
|
|
86
|
+
document.require_valid()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def normalize_units(root): ...
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
updated = document.transform(normalize_units)
|
|
93
|
+
updated.write("normalized.xml")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`Schema.compile` builds the schema once and generates its Python classes;
|
|
97
|
+
`schema.parse` binds an instance into a `Document` whose `report` holds
|
|
98
|
+
every issue found. A transform is any callable taking the tree root —
|
|
99
|
+
see the [quickstart](https://pyxsd.knorby.com/quickstart.html) and the
|
|
100
|
+
[full documentation](https://pyxsd.knorby.com/) for more.
|
|
101
|
+
|
|
102
|
+
## What it validates
|
|
103
|
+
|
|
104
|
+
All 45 XSD 1.0 built-in types with lexical validation; sequence/choice/all
|
|
105
|
+
content models; groups and attributeGroups (with refs); wildcards;
|
|
106
|
+
unions (including inline members); substitution groups; element refs;
|
|
107
|
+
`xsi:type` dispatch; `xsi:nil`; default/fixed; abstract/final; include /
|
|
108
|
+
import / redefine; `key`/`unique`/`keyref` with an XPath subset. Opt-in
|
|
109
|
+
namespace-aware validation (`--namespaces strict` / `ParseModes.NAMESPACED`)
|
|
110
|
+
handles `targetNamespace`, form defaults, cross-namespace imports, wildcard
|
|
111
|
+
namespace/`processContents`, and QName values. Facets on user-defined
|
|
112
|
+
simpleTypes are enforced (enumeration, pattern, length family, bounds,
|
|
113
|
+
digits, and whiteSpace), including values bound through `simpleContent`
|
|
114
|
+
complex types. Known
|
|
115
|
+
gaps are tabulated in the
|
|
116
|
+
[supported-features page](https://pyxsd.knorby.com/supported.html).
|
|
117
|
+
|
|
118
|
+
Backed by the W3C XML Schema Test Suite (xsdtests): pyxsd passes **99.78%**
|
|
119
|
+
of the XSD 1.1 profile and **99.61%** of the XSD 1.0 profile. For context,
|
|
120
|
+
the `xmlschema` library — the standard Python library in this space, and
|
|
121
|
+
pyxsd's conformance oracle — passes 99.75% (1.1) and 99.77% (1.0), but
|
|
122
|
+
declines (does not attempt) substantially more cases, so the percentages
|
|
123
|
+
are not directly comparable. Residual gaps are tabulated on the
|
|
124
|
+
[supported-features page](https://pyxsd.knorby.com/supported.html).
|
|
125
|
+
|
|
126
|
+
## Status
|
|
127
|
+
|
|
128
|
+
pyxsd was written at Oak Ridge National Laboratory in 2006 (see
|
|
129
|
+
[history](https://pyxsd.knorby.com/history/origins.html)),
|
|
130
|
+
abandoned around 2008, and revived as a Python 3 project in 2026.
|
|
131
|
+
Version 1.0.0 is the first release of the modernized library.
|
|
132
|
+
|
|
133
|
+
## Documentation
|
|
134
|
+
|
|
135
|
+
Full documentation is published at **<https://pyxsd.knorby.com/>**:
|
|
136
|
+
|
|
137
|
+
- [Quickstart](https://pyxsd.knorby.com/quickstart.html)
|
|
138
|
+
- [CLI reference](https://pyxsd.knorby.com/cli.html)
|
|
139
|
+
- [Architecture](https://pyxsd.knorby.com/architecture.html)
|
|
140
|
+
- [Data model](https://pyxsd.knorby.com/data-model.html)
|
|
141
|
+
- [Validation and issue codes](https://pyxsd.knorby.com/validation.html)
|
|
142
|
+
- [Parse modes](https://pyxsd.knorby.com/binding.html)
|
|
143
|
+
- [Transforms](https://pyxsd.knorby.com/transforms/)
|
|
144
|
+
- [Supported features](https://pyxsd.knorby.com/supported.html)
|
|
145
|
+
- [API reference](https://pyxsd.knorby.com/api.html)
|
|
146
|
+
- [Migrating from 0.1](https://pyxsd.knorby.com/migration-1.0.html)
|
|
147
|
+
- [Project history](https://pyxsd.knorby.com/history/origins.html)
|
|
148
|
+
- [Contributing](https://pyxsd.knorby.com/contributing.html)
|
|
149
|
+
|
|
150
|
+
The Sphinx sources live in `docs/`; build them locally with
|
|
151
|
+
`uv run sphinx-build -b html docs docs/_build/html`.
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
BSD 3-Clause. See [LICENSE](LICENSE) — it preserves the original ORNL
|
|
156
|
+
provenance note.
|