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.
Files changed (267) hide show
  1. pyxsd-1.0.0/.gitignore +44 -0
  2. pyxsd-1.0.0/CHANGELOG.md +319 -0
  3. pyxsd-1.0.0/LICENSE +29 -0
  4. pyxsd-1.0.0/PKG-INFO +156 -0
  5. pyxsd-1.0.0/README.md +128 -0
  6. pyxsd-1.0.0/docs/CNAME +1 -0
  7. pyxsd-1.0.0/docs/_static/.gitkeep +0 -0
  8. pyxsd-1.0.0/docs/_templates/.gitkeep +0 -0
  9. pyxsd-1.0.0/docs/api.md +79 -0
  10. pyxsd-1.0.0/docs/architecture.md +84 -0
  11. pyxsd-1.0.0/docs/binding.md +135 -0
  12. pyxsd-1.0.0/docs/cli.md +67 -0
  13. pyxsd-1.0.0/docs/comparison-xmlschema.md +109 -0
  14. pyxsd-1.0.0/docs/conf.py +60 -0
  15. pyxsd-1.0.0/docs/contributing.md +90 -0
  16. pyxsd-1.0.0/docs/data-model.md +110 -0
  17. pyxsd-1.0.0/docs/demo.md +104 -0
  18. pyxsd-1.0.0/docs/history/index.md +7 -0
  19. pyxsd-1.0.0/docs/history/origins.md +26 -0
  20. pyxsd-1.0.0/docs/index.md +43 -0
  21. pyxsd-1.0.0/docs/migration-1.0.md +343 -0
  22. pyxsd-1.0.0/docs/quickstart.md +114 -0
  23. pyxsd-1.0.0/docs/supported.md +190 -0
  24. pyxsd-1.0.0/docs/transforms/class.md +31 -0
  25. pyxsd-1.0.0/docs/transforms/index.md +15 -0
  26. pyxsd-1.0.0/docs/transforms/using.md +94 -0
  27. pyxsd-1.0.0/docs/transforms/writing.md +146 -0
  28. pyxsd-1.0.0/docs/validation.md +172 -0
  29. pyxsd-1.0.0/examples/README.md +45 -0
  30. pyxsd-1.0.0/examples/about_examples.md +79 -0
  31. pyxsd-1.0.0/examples/demo/.gitignore +5 -0
  32. pyxsd-1.0.0/examples/demo/CountElements.py +36 -0
  33. pyxsd-1.0.0/examples/demo/demo.py +57 -0
  34. pyxsd-1.0.0/examples/demo/instance.xml +16 -0
  35. pyxsd-1.0.0/examples/demo/schema.xsd +33 -0
  36. pyxsd-1.0.0/examples/docx/README.md +83 -0
  37. pyxsd-1.0.0/examples/docx/document.xml +180 -0
  38. pyxsd-1.0.0/examples/docx/download_schemas.py +117 -0
  39. pyxsd-1.0.0/examples/docx/expected.md +13 -0
  40. pyxsd-1.0.0/examples/docx/lax/README.md +51 -0
  41. pyxsd-1.0.0/examples/docx/lax/expected.md +6 -0
  42. pyxsd-1.0.0/examples/docx/lax/instance.xml +30 -0
  43. pyxsd-1.0.0/examples/docx/lax/schema.xsd +61 -0
  44. pyxsd-1.0.0/examples/docx/lax/to_markdown.py +72 -0
  45. pyxsd-1.0.0/examples/docx/to_markdown.py +231 -0
  46. pyxsd-1.0.0/examples/gpx/README.md +56 -0
  47. pyxsd-1.0.0/examples/gpx/download_schemas.py +85 -0
  48. pyxsd-1.0.0/examples/gpx/instance.xml +2217 -0
  49. pyxsd-1.0.0/examples/gpx/track_stats.py +129 -0
  50. pyxsd-1.0.0/examples/legacy/README.md +47 -0
  51. pyxsd-1.0.0/examples/legacy/atom.py +10 -0
  52. pyxsd-1.0.0/examples/legacy/bravais_lattice.py +10 -0
  53. pyxsd-1.0.0/examples/legacy/cell_sizer.py +118 -0
  54. pyxsd-1.0.0/examples/legacy/coord_viewer.py +27 -0
  55. pyxsd-1.0.0/examples/legacy/expand_cell.py +57 -0
  56. pyxsd-1.0.0/examples/legacy/format_for_visit.py +35 -0
  57. pyxsd-1.0.0/examples/legacy/sampleTransformFile.txt +3 -0
  58. pyxsd-1.0.0/examples/legacy/sphere_cutter.py +60 -0
  59. pyxsd-1.0.0/examples/legacy/vector.py +57 -0
  60. pyxsd-1.0.0/examples/musicxml/README.md +63 -0
  61. pyxsd-1.0.0/examples/musicxml/download_schemas.py +110 -0
  62. pyxsd-1.0.0/examples/musicxml/instance.xml +2131 -0
  63. pyxsd-1.0.0/examples/musicxml/note_stats.py +71 -0
  64. pyxsd-1.0.0/examples/transform_template_fromLibrary.py +25 -0
  65. pyxsd-1.0.0/examples/transform_template_fromTransform.py +32 -0
  66. pyxsd-1.0.0/examples/transform_template_library.py +21 -0
  67. pyxsd-1.0.0/pyproject.toml +152 -0
  68. pyxsd-1.0.0/src/pyxsd/__init__.py +74 -0
  69. pyxsd-1.0.0/src/pyxsd/__main__.py +6 -0
  70. pyxsd-1.0.0/src/pyxsd/alternatives.py +516 -0
  71. pyxsd-1.0.0/src/pyxsd/assertions.py +592 -0
  72. pyxsd-1.0.0/src/pyxsd/binding.py +104 -0
  73. pyxsd-1.0.0/src/pyxsd/cli.py +653 -0
  74. pyxsd-1.0.0/src/pyxsd/compositors.py +17 -0
  75. pyxsd-1.0.0/src/pyxsd/content_model.py +1205 -0
  76. pyxsd-1.0.0/src/pyxsd/derivation.py +356 -0
  77. pyxsd-1.0.0/src/pyxsd/dict_export.py +95 -0
  78. pyxsd-1.0.0/src/pyxsd/document.py +237 -0
  79. pyxsd-1.0.0/src/pyxsd/element_representatives/__init__.py +37 -0
  80. pyxsd-1.0.0/src/pyxsd/element_representatives/all.py +198 -0
  81. pyxsd-1.0.0/src/pyxsd/element_representatives/annotation.py +39 -0
  82. pyxsd-1.0.0/src/pyxsd/element_representatives/any.py +53 -0
  83. pyxsd-1.0.0/src/pyxsd/element_representatives/any_attribute.py +48 -0
  84. pyxsd-1.0.0/src/pyxsd/element_representatives/attribute.py +661 -0
  85. pyxsd-1.0.0/src/pyxsd/element_representatives/attribute_group.py +158 -0
  86. pyxsd-1.0.0/src/pyxsd/element_representatives/choice.py +70 -0
  87. pyxsd-1.0.0/src/pyxsd/element_representatives/complex_content.py +37 -0
  88. pyxsd-1.0.0/src/pyxsd/element_representatives/complex_type.py +543 -0
  89. pyxsd-1.0.0/src/pyxsd/element_representatives/documentation.py +58 -0
  90. pyxsd-1.0.0/src/pyxsd/element_representatives/element.py +759 -0
  91. pyxsd-1.0.0/src/pyxsd/element_representatives/element_representative.py +1658 -0
  92. pyxsd-1.0.0/src/pyxsd/element_representatives/enumeration.py +19 -0
  93. pyxsd-1.0.0/src/pyxsd/element_representatives/explicit_timezone.py +18 -0
  94. pyxsd-1.0.0/src/pyxsd/element_representatives/extension.py +86 -0
  95. pyxsd-1.0.0/src/pyxsd/element_representatives/fraction_digits.py +17 -0
  96. pyxsd-1.0.0/src/pyxsd/element_representatives/group.py +270 -0
  97. pyxsd-1.0.0/src/pyxsd/element_representatives/identity.py +532 -0
  98. pyxsd-1.0.0/src/pyxsd/element_representatives/length.py +17 -0
  99. pyxsd-1.0.0/src/pyxsd/element_representatives/list.py +122 -0
  100. pyxsd-1.0.0/src/pyxsd/element_representatives/max_exclusive.py +17 -0
  101. pyxsd-1.0.0/src/pyxsd/element_representatives/max_inclusive.py +17 -0
  102. pyxsd-1.0.0/src/pyxsd/element_representatives/max_length.py +17 -0
  103. pyxsd-1.0.0/src/pyxsd/element_representatives/min_exclusive.py +17 -0
  104. pyxsd-1.0.0/src/pyxsd/element_representatives/min_inclusive.py +17 -0
  105. pyxsd-1.0.0/src/pyxsd/element_representatives/min_length.py +17 -0
  106. pyxsd-1.0.0/src/pyxsd/element_representatives/notation.py +94 -0
  107. pyxsd-1.0.0/src/pyxsd/element_representatives/pattern.py +19 -0
  108. pyxsd-1.0.0/src/pyxsd/element_representatives/restriction.py +181 -0
  109. pyxsd-1.0.0/src/pyxsd/element_representatives/schema.py +133 -0
  110. pyxsd-1.0.0/src/pyxsd/element_representatives/sequence.py +47 -0
  111. pyxsd-1.0.0/src/pyxsd/element_representatives/simple_content.py +59 -0
  112. pyxsd-1.0.0/src/pyxsd/element_representatives/simple_type.py +79 -0
  113. pyxsd-1.0.0/src/pyxsd/element_representatives/total_digits.py +17 -0
  114. pyxsd-1.0.0/src/pyxsd/element_representatives/union.py +113 -0
  115. pyxsd-1.0.0/src/pyxsd/element_representatives/white_space.py +17 -0
  116. pyxsd-1.0.0/src/pyxsd/element_representatives/xsd_type.py +1255 -0
  117. pyxsd-1.0.0/src/pyxsd/exceptions.py +45 -0
  118. pyxsd-1.0.0/src/pyxsd/facets.py +1229 -0
  119. pyxsd-1.0.0/src/pyxsd/identity.py +1093 -0
  120. pyxsd-1.0.0/src/pyxsd/instance_binding.py +619 -0
  121. pyxsd-1.0.0/src/pyxsd/namespaces.py +194 -0
  122. pyxsd-1.0.0/src/pyxsd/nodes.py +39 -0
  123. pyxsd-1.0.0/src/pyxsd/open_content.py +706 -0
  124. pyxsd-1.0.0/src/pyxsd/particle_derivation.py +2007 -0
  125. pyxsd-1.0.0/src/pyxsd/regex_charset.py +176 -0
  126. pyxsd-1.0.0/src/pyxsd/schema.py +667 -0
  127. pyxsd-1.0.0/src/pyxsd/schema_base.py +2536 -0
  128. pyxsd-1.0.0/src/pyxsd/schema_checks.py +3528 -0
  129. pyxsd-1.0.0/src/pyxsd/schema_composition.py +1701 -0
  130. pyxsd-1.0.0/src/pyxsd/schema_context.py +160 -0
  131. pyxsd-1.0.0/src/pyxsd/schema_hints.py +164 -0
  132. pyxsd-1.0.0/src/pyxsd/transforms/__init__.py +18 -0
  133. pyxsd-1.0.0/src/pyxsd/transforms/displayer.py +40 -0
  134. pyxsd-1.0.0/src/pyxsd/transforms/print_data.py +27 -0
  135. pyxsd-1.0.0/src/pyxsd/transforms/to_dict.py +26 -0
  136. pyxsd-1.0.0/src/pyxsd/transforms/transform.py +215 -0
  137. pyxsd-1.0.0/src/pyxsd/tree.py +37 -0
  138. pyxsd-1.0.0/src/pyxsd/upa.py +322 -0
  139. pyxsd-1.0.0/src/pyxsd/validation.py +237 -0
  140. pyxsd-1.0.0/src/pyxsd/version_gates.py +103 -0
  141. pyxsd-1.0.0/src/pyxsd/versioning.py +268 -0
  142. pyxsd-1.0.0/src/pyxsd/wildcards.py +1120 -0
  143. pyxsd-1.0.0/src/pyxsd/writers/__init__.py +4 -0
  144. pyxsd-1.0.0/src/pyxsd/writers/xml_tag_writer.py +191 -0
  145. pyxsd-1.0.0/src/pyxsd/writers/xml_tree_writer.py +258 -0
  146. pyxsd-1.0.0/src/pyxsd/xpath_api.py +93 -0
  147. pyxsd-1.0.0/src/pyxsd/xpath_assertions.py +571 -0
  148. pyxsd-1.0.0/src/pyxsd/xpath_subset.py +227 -0
  149. pyxsd-1.0.0/src/pyxsd/xsd_data_types.py +1351 -0
  150. pyxsd-1.0.0/src/pyxsd/xsi.py +144 -0
  151. pyxsd-1.0.0/tests/conformance/cases.toml +9167 -0
  152. pyxsd-1.0.0/tests/conformance/unsupported.toml +65 -0
  153. pyxsd-1.0.0/tests/conformance_runner.py +169 -0
  154. pyxsd-1.0.0/tests/conftest.py +86 -0
  155. pyxsd-1.0.0/tests/fixtures/all/instance.xml +6 -0
  156. pyxsd-1.0.0/tests/fixtures/all/schema.xsd +12 -0
  157. pyxsd-1.0.0/tests/fixtures/choice/instance.xml +8 -0
  158. pyxsd-1.0.0/tests/fixtures/choice/schema.xsd +25 -0
  159. pyxsd-1.0.0/tests/fixtures/compose/common.xsd +15 -0
  160. pyxsd-1.0.0/tests/fixtures/compose/extra.xsd +8 -0
  161. pyxsd-1.0.0/tests/fixtures/compose/instance.xml +9 -0
  162. pyxsd-1.0.0/tests/fixtures/compose/redefined.xsd +9 -0
  163. pyxsd-1.0.0/tests/fixtures/compose/schema.xsd +28 -0
  164. pyxsd-1.0.0/tests/fixtures/datatypes/instance.xml +19 -0
  165. pyxsd-1.0.0/tests/fixtures/datatypes/schema.xsd +24 -0
  166. pyxsd-1.0.0/tests/fixtures/defaults/instance.xml +5 -0
  167. pyxsd-1.0.0/tests/fixtures/defaults/schema.xsd +16 -0
  168. pyxsd-1.0.0/tests/fixtures/groups/instance.xml +7 -0
  169. pyxsd-1.0.0/tests/fixtures/groups/schema.xsd +18 -0
  170. pyxsd-1.0.0/tests/fixtures/identity/instance.xml +11 -0
  171. pyxsd-1.0.0/tests/fixtures/identity/schema.xsd +43 -0
  172. pyxsd-1.0.0/tests/fixtures/inventory/instance.xml +16 -0
  173. pyxsd-1.0.0/tests/fixtures/inventory/schema.xsd +33 -0
  174. pyxsd-1.0.0/tests/fixtures/nested/instance.xml +15 -0
  175. pyxsd-1.0.0/tests/fixtures/nested/schema.xsd +29 -0
  176. pyxsd-1.0.0/tests/fixtures/nillable/instance.xml +5 -0
  177. pyxsd-1.0.0/tests/fixtures/nillable/schema.xsd +14 -0
  178. pyxsd-1.0.0/tests/fixtures/primitives/instance.xml +16 -0
  179. pyxsd-1.0.0/tests/fixtures/primitives/schema.xsd +20 -0
  180. pyxsd-1.0.0/tests/fixtures/substitution/instance.xml +6 -0
  181. pyxsd-1.0.0/tests/fixtures/substitution/schema.xsd +20 -0
  182. pyxsd-1.0.0/tests/fixtures/unions/instance.xml +6 -0
  183. pyxsd-1.0.0/tests/fixtures/unions/schema.xsd +23 -0
  184. pyxsd-1.0.0/tests/fixtures/wildcards/instance.xml +8 -0
  185. pyxsd-1.0.0/tests/fixtures/wildcards/schema.xsd +11 -0
  186. pyxsd-1.0.0/tests/fixtures/xsi_type/instance.xml +10 -0
  187. pyxsd-1.0.0/tests/fixtures/xsi_type/schema.xsd +32 -0
  188. pyxsd-1.0.0/tests/report_conformance.py +141 -0
  189. pyxsd-1.0.0/tests/report_xsts.py +188 -0
  190. pyxsd-1.0.0/tests/test_architecture.py +140 -0
  191. pyxsd-1.0.0/tests/test_cli.py +617 -0
  192. pyxsd-1.0.0/tests/test_composition.py +1348 -0
  193. pyxsd-1.0.0/tests/test_conformance.py +27 -0
  194. pyxsd-1.0.0/tests/test_conformance_runner.py +68 -0
  195. pyxsd-1.0.0/tests/test_content_model.py +463 -0
  196. pyxsd-1.0.0/tests/test_content_models.py +2344 -0
  197. pyxsd-1.0.0/tests/test_crash_elimination.py +700 -0
  198. pyxsd-1.0.0/tests/test_datatypes_coverage.py +688 -0
  199. pyxsd-1.0.0/tests/test_declaration_inheritance.py +176 -0
  200. pyxsd-1.0.0/tests/test_dict_export.py +90 -0
  201. pyxsd-1.0.0/tests/test_docs_examples.py +49 -0
  202. pyxsd-1.0.0/tests/test_document_api.py +164 -0
  203. pyxsd-1.0.0/tests/test_example_applications.py +339 -0
  204. pyxsd-1.0.0/tests/test_examples_transforms.py +99 -0
  205. pyxsd-1.0.0/tests/test_facets.py +646 -0
  206. pyxsd-1.0.0/tests/test_form_defaults.py +108 -0
  207. pyxsd-1.0.0/tests/test_generated_classes.py +166 -0
  208. pyxsd-1.0.0/tests/test_group_occurrences.py +107 -0
  209. pyxsd-1.0.0/tests/test_identity.py +1784 -0
  210. pyxsd-1.0.0/tests/test_identity_internals.py +541 -0
  211. pyxsd-1.0.0/tests/test_metamorphic.py +191 -0
  212. pyxsd-1.0.0/tests/test_misc_coverage.py +1141 -0
  213. pyxsd-1.0.0/tests/test_name_collision.py +143 -0
  214. pyxsd-1.0.0/tests/test_namespaces.py +1301 -0
  215. pyxsd-1.0.0/tests/test_nil_semantics.py +266 -0
  216. pyxsd-1.0.0/tests/test_nodes.py +19 -0
  217. pyxsd-1.0.0/tests/test_occurrence_values.py +803 -0
  218. pyxsd-1.0.0/tests/test_oracle.py +238 -0
  219. pyxsd-1.0.0/tests/test_parse_modes.py +217 -0
  220. pyxsd-1.0.0/tests/test_particle_binding.py +129 -0
  221. pyxsd-1.0.0/tests/test_particle_derivation.py +2792 -0
  222. pyxsd-1.0.0/tests/test_real_schema_support.py +128 -0
  223. pyxsd-1.0.0/tests/test_regex_charset.py +365 -0
  224. pyxsd-1.0.0/tests/test_release_gate.py +561 -0
  225. pyxsd-1.0.0/tests/test_round_trip.py +108 -0
  226. pyxsd-1.0.0/tests/test_schema_api.py +109 -0
  227. pyxsd-1.0.0/tests/test_schema_context.py +210 -0
  228. pyxsd-1.0.0/tests/test_schema_legality.py +3554 -0
  229. pyxsd-1.0.0/tests/test_send_tree_observability.py +59 -0
  230. pyxsd-1.0.0/tests/test_structural_schema.py +322 -0
  231. pyxsd-1.0.0/tests/test_substitution_groups.py +236 -0
  232. pyxsd-1.0.0/tests/test_transform_framework.py +246 -0
  233. pyxsd-1.0.0/tests/test_type_lattice_integration.py +136 -0
  234. pyxsd-1.0.0/tests/test_type_resolution.py +504 -0
  235. pyxsd-1.0.0/tests/test_upa.py +319 -0
  236. pyxsd-1.0.0/tests/test_upa_internals.py +70 -0
  237. pyxsd-1.0.0/tests/test_validation.py +358 -0
  238. pyxsd-1.0.0/tests/test_version_gates.py +83 -0
  239. pyxsd-1.0.0/tests/test_versioning.py +59 -0
  240. pyxsd-1.0.0/tests/test_wildcard_associations.py +215 -0
  241. pyxsd-1.0.0/tests/test_wildcard_attributes.py +895 -0
  242. pyxsd-1.0.0/tests/test_wildcard_particles.py +401 -0
  243. pyxsd-1.0.0/tests/test_wildcards_11.py +1333 -0
  244. pyxsd-1.0.0/tests/test_wildcards_algebra.py +132 -0
  245. pyxsd-1.0.0/tests/test_write_through.py +99 -0
  246. pyxsd-1.0.0/tests/test_writer_cli_edges.py +80 -0
  247. pyxsd-1.0.0/tests/test_writer_escaping.py +136 -0
  248. pyxsd-1.0.0/tests/test_xpath_api.py +85 -0
  249. pyxsd-1.0.0/tests/test_xsd11_coverage.py +977 -0
  250. pyxsd-1.0.0/tests/test_xsd11_features.py +1679 -0
  251. pyxsd-1.0.0/tests/test_xsd_data_types.py +819 -0
  252. pyxsd-1.0.0/tests/test_xsts_catalog.py +153 -0
  253. pyxsd-1.0.0/tests/test_xsts_outcomes.py +90 -0
  254. pyxsd-1.0.0/tests/test_xsts_runner.py +625 -0
  255. pyxsd-1.0.0/tests/test_xsts_selection.py +87 -0
  256. pyxsd-1.0.0/tests/test_xsts_suite.py +58 -0
  257. pyxsd-1.0.0/tests/xsts/README.md +134 -0
  258. pyxsd-1.0.0/tests/xsts/__init__.py +16 -0
  259. pyxsd-1.0.0/tests/xsts/baseline-xsd10.toml +41740 -0
  260. pyxsd-1.0.0/tests/xsts/baseline-xsd11.toml +83475 -0
  261. pyxsd-1.0.0/tests/xsts/baseline.py +150 -0
  262. pyxsd-1.0.0/tests/xsts/catalog.py +360 -0
  263. pyxsd-1.0.0/tests/xsts/drivers.py +576 -0
  264. pyxsd-1.0.0/tests/xsts/outcomes.py +91 -0
  265. pyxsd-1.0.0/tests/xsts/report.py +150 -0
  266. pyxsd-1.0.0/tests/xsts/runner.py +458 -0
  267. 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
@@ -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
+ [![CI](https://github.com/knorby/pyxsd/actions/workflows/ci.yml/badge.svg)](https://github.com/knorby/pyxsd/actions/workflows/ci.yml)
32
+ [![Docs](https://github.com/knorby/pyxsd/actions/workflows/docs.yml/badge.svg)](https://github.com/knorby/pyxsd/actions/workflows/docs.yml)
33
+ [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue)](https://pypi.org/project/pyxsd/)
34
+ [![PyPI](https://img.shields.io/pypi/v/pyxsd)](https://pypi.org/project/pyxsd/)
35
+ [![Docs](https://img.shields.io/badge/docs-pyxsd.knorby.com-blue)](https://pyxsd.knorby.com/)
36
+ [![License](https://img.shields.io/badge/license-BSD--3--Clause-blue)](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.