datex2-xml2json 0.0.1__tar.gz → 0.0.4__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 (68) hide show
  1. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/PKG-INFO +9 -9
  2. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/README.md +2 -2
  3. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/pyproject.toml +53 -51
  4. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/pyproject.toml.orig +16 -13
  5. datex2_xml2json-0.0.4/src/datex2_xml2json/_version.py +1 -0
  6. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/json_validator.py +6 -3
  7. datex2_xml2json-0.0.4/src/datex2_xml2json/py.typed +0 -0
  8. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/__init__.py +3 -2
  9. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/base.py +17 -13
  10. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/cifs_transformer.py +29 -24
  11. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/geojson_geometry_transformer.py +10 -8
  12. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/geoparquet_transformer.py +30 -14
  13. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/jsonata_transformer.py +5 -3
  14. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/roads_regio_transformer.py +8 -6
  15. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/source_setter.py +5 -15
  16. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/transformation_rules.py +23 -20
  17. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transformer.py +62 -24
  18. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/util.py +28 -13
  19. datex2_xml2json-0.0.1/src/datex2_xml2json/schema/Baustellen-4-00-00.sch +0 -7
  20. datex2_xml2json-0.0.1/src/datex2_xml2json/schema/DATEXII_3.7_Profile/.DS_Store +0 -0
  21. datex2_xml2json-0.0.1/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/.DS_Store +0 -0
  22. datex2_xml2json-0.0.1/src/datex2_xml2json/transform/.DS_Store +0 -0
  23. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/LICENSE.md +0 -0
  24. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/__init__.py +0 -0
  25. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/merge.py +0 -0
  26. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXIISchema_2_2_0.xsd +0 -0
  27. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXIISchema_2_2_3.xsd +0 -0
  28. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_AfirEnergyInfrastructure.json +0 -0
  29. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_AfirFacilities.json +0 -0
  30. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Common.json +0 -0
  31. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_CommonExtension.json +0 -0
  32. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_ControlledZone.json +0 -0
  33. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_D2Payload.json +0 -0
  34. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_EnergyInfrastructure.json +0 -0
  35. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Facilities.json +0 -0
  36. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_FaultAndStatus.json +0 -0
  37. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_LocationExtension.json +0 -0
  38. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_LocationReferencing.json +0 -0
  39. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Parking.json +0 -0
  40. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_ReroutingManagementEnhanced.json +0 -0
  41. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_RoadTrafficData.json +0 -0
  42. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Situation.json +0 -0
  43. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_TrafficManagementPlan.json +0 -0
  44. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_TrafficRegulation.json +0 -0
  45. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_UrbanExtensions.json +0 -0
  46. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Vms.json +0 -0
  47. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_AfirEnergyInfrastructure.xsd +0 -0
  48. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_AfirFacilities.xsd +0 -0
  49. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_Common.xsd +0 -0
  50. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_CommonExtension.xsd +0 -0
  51. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_ControlledZone.xsd +0 -0
  52. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_D2Payload.xsd +0 -0
  53. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_EnergyInfrastructure.xsd +0 -0
  54. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_Facilities.xsd +0 -0
  55. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_FaultAndStatus.xsd +0 -0
  56. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_LocationExtension.xsd +0 -0
  57. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_LocationReferencing.xsd +0 -0
  58. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_Parking.xsd +0 -0
  59. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_ReroutingManagementEnhanced.xsd +0 -0
  60. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_RoadTrafficData.xsd +0 -0
  61. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_Situation.xsd +0 -0
  62. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_TrafficManagementPlan.xsd +0 -0
  63. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_TrafficRegulation.xsd +0 -0
  64. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_UrbanExtensions.xsd +0 -0
  65. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/DATEXII_3_Vms.xsd +0 -0
  66. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/MDM_BaustellenInfoDigitalRoadworksProfile_04-03-00.xsd +0 -0
  67. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/MDM_Datenmodell_Baustellen_04-00-00.xsd +0 -0
  68. {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/cifs_schema.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datex2-xml2json
3
- Version: 0.0.1
3
+ Version: 0.0.4
4
4
  Summary: PoC converting DATEX2 v2 (situation) publications to various output formats.
5
5
  Keywords: DATEX2,roadworks,road closures,GeoJSON,Geoparquet,WAZE-CIFS
6
6
  Author: Holger Bruch
@@ -12,12 +12,12 @@ Classifier: Intended Audience :: Developers
12
12
  Classifier: Topic :: File Formats
13
13
  Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Operating System :: OS Independent
15
- Requires-Dist: jsonschema>=4.26.0
16
- Requires-Dist: check-jsonschema>=0.38.2
17
- Requires-Dist: jsonata-python>=0.7.0
18
- Requires-Dist: geoparquet-io>=1.6.0
19
- Requires-Dist: pyarrow>=26.0.0
20
- Requires-Dist: rs-xml2json>=0.2.0
15
+ Requires-Dist: jsonschema>=4.26,<5
16
+ Requires-Dist: check-jsonschema>=0.38,<1
17
+ Requires-Dist: jsonata-python>=0.7.0,<1
18
+ Requires-Dist: geoparquet-io>=1.7,<2
19
+ Requires-Dist: pyarrow>=26,<27
20
+ Requires-Dist: rs-xml2json~=0.2.0
21
21
  Requires-Python: >=3.12
22
22
  Project-URL: Homepage, https://github.com/datex2-tools/datex2-xml2json
23
23
  Project-URL: Issues, https://github.com/datex2-tools/datex2-xml2json/issues
@@ -163,8 +163,8 @@ Easiest way to learn about it, is starting with an existing transformation using
163
163
 
164
164
  E.g. you could start with the following to example transformations (which might not exactly reflect the latest code version of this project):
165
165
 
166
- * https://try.jsonata.org/Gk5r-kLek: Mapping DATEX3.7LiteJSON to DATEX2MostlyFlatGeoJSON (Current JSONata expression is in datex2_xml2json/transform/jsonata_transformer.py)
167
- * https://try.jsonata.org/QEnqmItyF: Mapping DATEX2MostlyFlatGeoJSON to (mostly) WAZE CIFS (Current JSONata expression is in datex2_xml2json/transform/cifs_transformer.py)
166
+ * https://try.jsonata.org/Gk5r-kLek: Mapping DATEX3.7LiteJSON to DATEX2MostlyFlatGeoJSON (Current JSONata expression is in `src/datex2_xml2json/transform/jsonata_transformer.py`)
167
+ * https://try.jsonata.org/QEnqmItyF: Mapping DATEX2MostlyFlatGeoJSON to (mostly) WAZE CIFS (Current JSONata expression is in `src/datex2_xml2json/transform/cifs_transformer.py`)
168
168
 
169
169
  ### Running tests
170
170
 
@@ -138,8 +138,8 @@ Easiest way to learn about it, is starting with an existing transformation using
138
138
 
139
139
  E.g. you could start with the following to example transformations (which might not exactly reflect the latest code version of this project):
140
140
 
141
- * https://try.jsonata.org/Gk5r-kLek: Mapping DATEX3.7LiteJSON to DATEX2MostlyFlatGeoJSON (Current JSONata expression is in datex2_xml2json/transform/jsonata_transformer.py)
142
- * https://try.jsonata.org/QEnqmItyF: Mapping DATEX2MostlyFlatGeoJSON to (mostly) WAZE CIFS (Current JSONata expression is in datex2_xml2json/transform/cifs_transformer.py)
141
+ * https://try.jsonata.org/Gk5r-kLek: Mapping DATEX3.7LiteJSON to DATEX2MostlyFlatGeoJSON (Current JSONata expression is in `src/datex2_xml2json/transform/jsonata_transformer.py`)
142
+ * https://try.jsonata.org/QEnqmItyF: Mapping DATEX2MostlyFlatGeoJSON to (mostly) WAZE CIFS (Current JSONata expression is in `src/datex2_xml2json/transform/cifs_transformer.py`)
143
143
 
144
144
  ### Running tests
145
145
 
@@ -1,56 +1,9 @@
1
1
  [build-system]
2
- requires = ["uv_build >= 0.12.19"]
2
+ requires = ["uv_build >= 0.12.19, <1"]
3
3
  build-backend = "uv_build"
4
4
 
5
- [project]
6
- name = "datex2-xml2json"
7
- version = "0.0.1"
8
- description = "PoC converting DATEX2 v2 (situation) publications to various output formats."
9
- readme = "README.md"
10
- keywords = [
11
- "DATEX2",
12
- "roadworks",
13
- "road closures",
14
- "GeoJSON",
15
- "Geoparquet",
16
- "WAZE-CIFS",
17
- ]
18
- requires-python = ">=3.12"
19
- classifiers = [
20
- "Development Status :: 3 - Alpha",
21
- "Intended Audience :: Developers",
22
- "Topic :: File Formats",
23
- "Programming Language :: Python :: 3",
24
- "Operating System :: OS Independent",
25
- ]
26
- license = "EUPL-1.2"
27
- license-files = ["LICENSE.md"]
28
- dependencies = [
29
- "jsonschema>=4.26.0",
30
- "check-jsonschema>=0.38.2",
31
- "jsonata-python>=0.7.0",
32
- "geoparquet-io>=1.6.0",
33
- "pyarrow>=26.0.0",
34
- "rs-xml2json>=0.2.0",
35
- ]
36
-
37
- [[project.authors]]
38
- name = "Holger Bruch"
39
- email = "hb@mfdz.de"
40
-
41
- [project.urls]
42
- Homepage = "https://github.com/datex2-tools/datex2-xml2json"
43
- Issues = "https://github.com/datex2-tools/datex2-xml2json/issues"
44
-
45
- [dependency-groups]
46
- dev = [
47
- "pytest~=9.1.1",
48
- "ruff~=0.17.2",
49
- "mypy~=2.3.1",
50
- "pre-commit>=4.3.0",
51
- "types-shapely~=2.1.0.20260728",
52
- "pyarrow-stubs~=20.0.0.20260819",
53
- ]
5
+ [tool.uv.build-backend]
6
+ source-exclude = [".DS_Store"]
54
7
 
55
8
  [tool.ruff]
56
9
  line-length = 140
@@ -174,6 +127,7 @@ testpaths = ["tests"]
174
127
 
175
128
  [tool.mypy]
176
129
  python_version = "3.12"
130
+ strict = true
177
131
 
178
132
  [[tool.mypy.overrides]]
179
133
  module = [
@@ -188,6 +142,54 @@ module = [
188
142
  "geoparquet_io",
189
143
  "rs_xml2json",
190
144
  "pyarrow",
191
- "shapely.geometry",
145
+ "pyarrow.parquet",
192
146
  ]
193
147
  ignore_missing_imports = true
148
+
149
+ [project]
150
+ name = "datex2-xml2json"
151
+ version = "0.0.4"
152
+ description = "PoC converting DATEX2 v2 (situation) publications to various output formats."
153
+ readme = "README.md"
154
+ keywords = [
155
+ "DATEX2",
156
+ "roadworks",
157
+ "road closures",
158
+ "GeoJSON",
159
+ "Geoparquet",
160
+ "WAZE-CIFS",
161
+ ]
162
+ requires-python = ">=3.12"
163
+ classifiers = [
164
+ "Development Status :: 3 - Alpha",
165
+ "Intended Audience :: Developers",
166
+ "Topic :: File Formats",
167
+ "Programming Language :: Python :: 3",
168
+ "Operating System :: OS Independent",
169
+ ]
170
+ license = "EUPL-1.2"
171
+ license-files = ["LICENSE.md"]
172
+ dependencies = [
173
+ "jsonschema>=4.26,<5",
174
+ "check-jsonschema>=0.38,<1",
175
+ "jsonata-python>=0.7.0,<1",
176
+ "geoparquet-io>=1.7,<2",
177
+ "pyarrow>=26,<27",
178
+ "rs-xml2json~=0.2.0",
179
+ ]
180
+
181
+ [[project.authors]]
182
+ name = "Holger Bruch"
183
+ email = "hb@mfdz.de"
184
+
185
+ [project.urls]
186
+ Homepage = "https://github.com/datex2-tools/datex2-xml2json"
187
+ Issues = "https://github.com/datex2-tools/datex2-xml2json/issues"
188
+
189
+ [dependency-groups]
190
+ dev = [
191
+ "pytest>=9.1.1,<10",
192
+ "ruff~=0.17.2",
193
+ "mypy~=2.3.1",
194
+ "pre-commit>=4.3.0,<5",
195
+ ]
@@ -1,10 +1,14 @@
1
1
  [build-system]
2
- requires = ["uv_build >= 0.12.19"]
2
+ requires = ["uv_build >= 0.12.19, <1"]
3
3
  build-backend = "uv_build"
4
4
 
5
+ [tool.uv.build-backend]
6
+ source-exclude = [".DS_Store"]
7
+
5
8
  [project]
6
9
  name = "datex2-xml2json"
7
- version = "0.0.1"
10
+ # The version is bumped from the git tag in CI via `uv version` on release; see .github/workflows/test_build_and_publish.yml
11
+ version = "0.0.4"
8
12
  authors = [
9
13
  { name="Holger Bruch", email="hb@mfdz.de" },
10
14
  ]
@@ -23,23 +27,21 @@ license = "EUPL-1.2"
23
27
  license-files = ["LICENSE.md"]
24
28
 
25
29
  dependencies = [
26
- "jsonschema>=4.26.0",
27
- "check-jsonschema>=0.38.2",
28
- "jsonata-python>=0.7.0",
29
- "geoparquet-io>=1.6.0",
30
- "pyarrow>=26.0.0",
31
- "rs-xml2json>=0.2.0"
30
+ "jsonschema>=4.26,<5",
31
+ "check-jsonschema>=0.38,<1",
32
+ "jsonata-python>=0.7.0,<1",
33
+ "geoparquet-io>=1.7,<2",
34
+ "pyarrow>=26,<27",
35
+ "rs-xml2json~=0.2.0"
32
36
  ]
33
37
 
34
38
  # Development and test dependencies (PEP 735 dependency group, installed by `uv sync`).
35
39
  [dependency-groups]
36
40
  dev = [
37
- "pytest~=9.1.1",
41
+ "pytest>=9.1.1,<10",
38
42
  "ruff~=0.17.2",
39
43
  "mypy~=2.3.1",
40
- "pre-commit>=4.3.0",
41
- "types-shapely~=2.1.0.20260728",
42
- "pyarrow-stubs~=20.0.0.20260819",
44
+ "pre-commit>=4.3.0,<5"
43
45
  ]
44
46
 
45
47
  [project.urls]
@@ -129,6 +131,7 @@ testpaths = ["tests"]
129
131
 
130
132
  [tool.mypy]
131
133
  python_version = "3.12"
134
+ strict = true
132
135
 
133
136
  [[tool.mypy.overrides]]
134
137
  module = [
@@ -143,6 +146,6 @@ module = [
143
146
  "geoparquet_io",
144
147
  "rs_xml2json",
145
148
  "pyarrow",
146
- "shapely.geometry",
149
+ "pyarrow.parquet",
147
150
  ]
148
151
  ignore_missing_imports = true
@@ -0,0 +1 @@
1
+ __version__ = '0.0.4'
@@ -1,3 +1,5 @@
1
+ from pathlib import Path
2
+
1
3
  from check_jsonschema.checker import SchemaChecker
2
4
  from check_jsonschema.file_wrapper import BinaryFileInput
3
5
  from check_jsonschema.formats import FormatOptions
@@ -8,7 +10,7 @@ from check_jsonschema.schema_loader import SchemaLoader
8
10
 
9
11
 
10
12
  class JsonValidator:
11
- def __init__(self, schema_path):
13
+ def __init__(self, schema_path: str) -> None:
12
14
  self.schema_loader = SchemaLoader(
13
15
  schema_path,
14
16
  disable_cache=False,
@@ -20,7 +22,7 @@ class JsonValidator:
20
22
  cls = REPORTER_BY_NAME[output_format]
21
23
  return cls(verbosity=verbosity)
22
24
 
23
- def validate(self, filename):
25
+ def validate(self, filename: str | Path) -> int:
24
26
  checker = SchemaChecker(
25
27
  schema_loader=self.schema_loader,
26
28
  instance_loader=InstanceLoader([BinaryFileInput(filename)]),
@@ -33,4 +35,5 @@ class JsonValidator:
33
35
  regex_impl=RegexImplementation(RegexVariantName.default),
34
36
  )
35
37
 
36
- return checker.run()
38
+ result: int = checker.run()
39
+ return result
File without changes
@@ -1,4 +1,5 @@
1
1
  from .base import (
2
+ AbstractTransformer as AbstractTransformer,
2
3
  TransformerPipeline as TransformerPipeline,
3
4
  RulesTransformer as RulesTransformer,
4
5
  )
@@ -9,5 +10,5 @@ from .geojson_geometry_transformer import (
9
10
  GeoJSONGeometryTransformer as GeoJSONGeometryTransformer,
10
11
  )
11
12
  from .geoparquet_transformer import GeoparquetRenderer as GeoparquetRenderer
12
- from .cifs_transformer import CifsTransformer
13
- from .source_setter import SourceSetter
13
+ from .cifs_transformer import CifsTransformer as CifsTransformer
14
+ from .source_setter import SourceSetter as SourceSetter
@@ -1,22 +1,24 @@
1
- from datex2_xml2json.util import replace, xpath_dict
1
+ from typing import Self
2
+
3
+ from datex2_xml2json.util import JsonDict, replace, xpath_dict
2
4
 
3
5
  from .transformation_rules import TransformationRules
4
6
 
5
7
 
6
8
  class AbstractTransformer:
7
- def transform(self, a_dict: dict) -> dict:
9
+ def transform(self, a_dict: JsonDict) -> JsonDict:
8
10
  return a_dict
9
11
 
10
12
 
11
13
  class TransformerPipeline(AbstractTransformer):
12
- def __init__(self, transformers: list[AbstractTransformer]):
14
+ def __init__(self, transformers: list[AbstractTransformer]) -> None:
13
15
  self.transformers = list(transformers)
14
16
 
15
- def add_transformer(self, transformer: AbstractTransformer):
17
+ def add_transformer(self, transformer: AbstractTransformer) -> Self:
16
18
  self.transformers.append(transformer)
17
19
  return self
18
20
 
19
- def transform(self, a_dict: dict) -> dict:
21
+ def transform(self, a_dict: JsonDict) -> JsonDict:
20
22
  result = a_dict
21
23
  for t in self.transformers:
22
24
  result = t.transform(result)
@@ -28,7 +30,7 @@ class RulesTransformer(AbstractTransformer):
28
30
  def __init__(self, rules: TransformationRules):
29
31
  self.rules = rules
30
32
 
31
- def transform(self, a_dict: dict) -> dict:
33
+ def transform(self, a_dict: JsonDict) -> JsonDict:
32
34
  # Transforms the result of xml2json transformation into DATEXIIv3 json.
33
35
  # This includes:
34
36
  # * renamings of certain properties according to v2 to v3 name changes
@@ -36,7 +38,7 @@ class RulesTransformer(AbstractTransformer):
36
38
  # * casts values of certain properties to intended types
37
39
  # * ...
38
40
 
39
- return replace(
41
+ result: JsonDict = replace(
40
42
  a_dict,
41
43
  None,
42
44
  self.rules.renamings,
@@ -46,29 +48,31 @@ class RulesTransformer(AbstractTransformer):
46
48
  self.rules.keys_to_pull_up,
47
49
  )
48
50
 
51
+ return result
52
+
49
53
 
50
54
  class ProcessingTransformer(AbstractTransformer):
51
- def __init__(self, xpath: str):
55
+ def __init__(self, xpath: str) -> None:
52
56
  self.xpath = xpath
53
57
 
54
- def transform(self, a_dict: dict) -> dict:
58
+ def transform(self, a_dict: JsonDict) -> JsonDict:
55
59
  for elem in xpath_dict(a_dict, self.xpath):
56
60
  self.process(elem)
57
61
 
58
62
  return a_dict
59
63
 
60
- def process(self, a_dict: dict):
64
+ def process(self, a_dict: JsonDict) -> None:
61
65
  pass
62
66
 
63
67
 
64
68
  class SituationRecordTransformer(ProcessingTransformer):
65
- def __init__(self, xpath: str):
69
+ def __init__(self, xpath: str) -> None:
66
70
  super().__init__(xpath)
67
71
 
68
- def process_situation_record(self, situation_record: dict) -> None:
72
+ def process_situation_record(self, situation_record: JsonDict) -> None:
69
73
  pass
70
74
 
71
- def process(self, situation_record_wrapper: dict) -> None:
75
+ def process(self, situation_record_wrapper: JsonDict) -> None:
72
76
  if isinstance(situation_record_wrapper, dict) and len(situation_record_wrapper) == 1:
73
77
  situation_record = situation_record_wrapper.get(next(iter(situation_record_wrapper.keys())))
74
78
  else:
@@ -2,6 +2,8 @@ import copy
2
2
  import logging
3
3
  import re
4
4
 
5
+ from datex2_xml2json.util import JsonDict
6
+
5
7
  from .jsonata_transformer import JsonataTransformer
6
8
 
7
9
  logger = logging.getLogger(__name__)
@@ -58,7 +60,7 @@ cifs_expression = """
58
60
  "DisturbanceActivity": "CHIT_CHAT",
59
61
  "TransitInformation": "CHIT_CHAT"
60
62
  };
61
- $lookup($typeBySubtypeLookup , properties.situationRecordSubtype)?:$lookup($typeLookup , properties.type)?:"TODO"),
63
+ $lookup($typeBySubtypeLookup , properties.situationRecordSubtype)?:$lookup($typeLookup , properties.type)?:"HAZARD"),
62
64
  "subtype": (
63
65
  $subtypeByTypeLookup := {
64
66
  /* Accident (no subtypes, as DATEXII does not provide accident severity) */
@@ -134,6 +136,12 @@ cifs_expression = """
134
136
  }
135
137
  """
136
138
 
139
+ # In case multiple incidents describe the same situation, usually because of an caused/effect relation,
140
+ # we pick the incident, whose type/subtype are ranked highest (most informative/important)
141
+ DEFAULT_INCIDENT_PRIORITY = 1
142
+ TYPE_PRIORITIES = {'ROAD_CLOSED': 10, 'ACCIDENT': 9, 'JAM': 8, 'HAZARD': 7, 'POLICE': 2, 'CHIT_CHAT': 1}
143
+ SUBTYPE_PRIORITIES = {'ROAD_CLOSED': 10, 'ACCIDENT': 9, 'JAM': 8, 'HAZARD': 7, 'POLICE': 2, 'CHIT_CHAT': 1}
144
+
137
145
 
138
146
  class CifsTransformer(JsonataTransformer):
139
147
  # This pattern is used to exract the common ID prefix of all situation records which
@@ -143,11 +151,11 @@ class CifsTransformer(JsonataTransformer):
143
151
  # 2. Any string/char prefix followed by dot + number
144
152
  situation_record_group_prefix_regexp = r'^(\d+-\d\d\d\dV\d+)$|^(\d+-\d+-\d+-\d+-gegen).*|^(\d+-\d+-\d+-\d+).*|^(.*)\.\d+$'
145
153
 
146
- def __init__(self, **kwargs):
154
+ def __init__(self) -> None:
147
155
  super().__init__(cifs_expression)
148
156
 
149
- def _group_by_common_situation_record_id_substring(self, incidents, pattern):
150
- grouped_incidents = {}
157
+ def _group_by_common_situation_record_id_substring(self, incidents: list[JsonDict], pattern: str) -> dict[str, list[JsonDict]]:
158
+ grouped_incidents: dict[str, list[JsonDict]] = {}
151
159
  p = re.compile(pattern)
152
160
 
153
161
  for incident in incidents:
@@ -163,19 +171,13 @@ class CifsTransformer(JsonataTransformer):
163
171
 
164
172
  return grouped_incidents
165
173
 
166
- def _get_type_sub_type_prio(self, incident):
167
- if incident.get('type') == 'ROAD_CLOSED':
168
- return 10
169
- if incident.get('subtype') == 'HAZARD_ON_ROAD_LANE_CLOSED':
170
- return 4
171
- if incident.get('subtype') == 'HAZARD_ON_ROAD_CONSTRUCTION':
172
- return 3
173
- if incident.get('subtype') == 'HAZARD_ON_ROAD' or incident.get('type') in ['CHIT_CHAT']:
174
- return 1
175
- else:
176
- return 2
174
+ def _get_type_sub_type_prio(self, incident: JsonDict) -> int:
175
+ return max(
176
+ TYPE_PRIORITIES.get(str(incident.get('type')), DEFAULT_INCIDENT_PRIORITY),
177
+ SUBTYPE_PRIORITIES.get(str(incident.get('subtype')), DEFAULT_INCIDENT_PRIORITY),
178
+ )
177
179
 
178
- def _merge_incident_group(self, incident_group):
180
+ def _merge_incident_group(self, incident_group: list[JsonDict]) -> JsonDict:
179
181
  # Assumptions: besides type and subtype, all properties are assumed to be equals
180
182
  # (TODO: we might check this explicitly)
181
183
  #
@@ -184,30 +186,33 @@ class CifsTransformer(JsonataTransformer):
184
186
  # * highest priority subtype/type wins
185
187
  # TODO: subtype for road_closed to be set according to other incidents
186
188
  # TODO: should jam be communicated in addition?
189
+ if not incident_group:
190
+ raise ValueError('incident_group must not be empty')
191
+
187
192
  highest_prio = None
188
193
  highest_prio_type = None
189
194
  highest_prio_subtype = None
190
- highest_prio_incident = None
195
+ highest_prio_incident: JsonDict = incident_group[0]
191
196
 
192
197
  for incident in incident_group:
193
198
  current_prio = self._get_type_sub_type_prio(incident)
194
199
  if highest_prio is None or current_prio > highest_prio:
195
200
  logger.debug(
196
201
  f'For {incident["id"]}, replace {highest_prio} {highest_prio_type} {highest_prio_subtype}'
197
- f' by {incident["type"]} {incident.get("subtype")}'
202
+ f' by {incident.get("type")} {incident.get("subtype")}'
198
203
  )
199
204
  highest_prio = current_prio
200
- highest_prio_type = incident['type']
205
+ highest_prio_type = incident.get('type')
201
206
  highest_prio_subtype = incident.get('subtype')
202
207
  highest_prio_incident = incident
203
208
  else:
204
209
  logger.debug(
205
210
  f'For {incident["id"]}, do not replace {highest_prio} {highest_prio_type} {highest_prio_subtype}'
206
- f' by {incident["type"]} {incident.get("subtype")}'
211
+ f' by {incident.get("type")} {incident.get("subtype")}'
207
212
  )
208
213
  return highest_prio_incident
209
214
 
210
- def _transform_polyline_geom(self, linestring_coordinates) -> str:
215
+ def _transform_polyline_geom(self, linestring_coordinates: list[list[float]]) -> str:
211
216
  """
212
217
  Converts GeoJSON linestring coordinates array into CIFS polyline string.
213
218
  The list of lon/lat coords (like [[10.0, 49.0], [11.0, 49.0]]) is converted into a
@@ -215,7 +220,7 @@ class CifsTransformer(JsonataTransformer):
215
220
  """
216
221
  return ' '.join([f'{coords[1]} {coords[0]}' for coords in linestring_coordinates])
217
222
 
218
- def _transform_incident_geometry(self, incident: dict) -> list[dict]:
223
+ def _transform_incident_geometry(self, incident: JsonDict) -> list[JsonDict]:
219
224
  """
220
225
  Converts GeoJSON geometry of incident into a CIFS polyline.
221
226
  As the GeoJSON geometry might be a MultiLineString, we return an array
@@ -248,7 +253,7 @@ class CifsTransformer(JsonataTransformer):
248
253
 
249
254
  return [incident]
250
255
 
251
- def _merge_grouped_incidents_and_handle_geometry(self, grouped_incidents):
256
+ def _merge_grouped_incidents_and_handle_geometry(self, grouped_incidents: dict[str, list[JsonDict]]) -> list[JsonDict]:
252
257
  incidents = []
253
258
  for key in grouped_incidents:
254
259
  try:
@@ -260,7 +265,7 @@ class CifsTransformer(JsonataTransformer):
260
265
 
261
266
  return incidents
262
267
 
263
- def post_transform(self, a_dict: dict) -> dict:
268
+ def post_transform(self, a_dict: JsonDict) -> JsonDict:
264
269
  """
265
270
  Retains the most expressive incident of a group of incidents describing
266
271
  the same situation.
@@ -1,5 +1,7 @@
1
1
  import logging
2
2
 
3
+ from datex2_xml2json.util import JsonDict
4
+
3
5
  from .base import SituationRecordTransformer
4
6
 
5
7
  logger = logging.getLogger(__name__)
@@ -14,7 +16,7 @@ class GeoJSONGeometryTransformer(SituationRecordTransformer):
14
16
  super().__init__(situation_record_json_pointer)
15
17
  self.geom_container_element_json_point = geom_container_element_json_point
16
18
 
17
- def _extract_coordinates_from_gmlLineString(self, gmlLineString: dict) -> list:
19
+ def _extract_coordinates_from_gmlLineString(self, gmlLineString: JsonDict) -> list[list[float]]:
18
20
  # Coordinate Order Confusion
19
21
  # There is often some confusion regarding the correct ordering of coordinate values.
20
22
  # While EPSG:4326 usually uses lat,lon ordering, and CRS84 (and GeoJSON) use lon/lat,
@@ -38,7 +40,7 @@ class GeoJSONGeometryTransformer(SituationRecordTransformer):
38
40
  else:
39
41
  return [[lon, lat] for lon, lat in zipped_coords]
40
42
 
41
- def _extract_line_geom(self, linearExtended: dict) -> None | dict:
43
+ def _extract_line_geom(self, linearExtended: JsonDict) -> None | JsonDict:
42
44
  gmlLineString = linearExtended.get('gmlLineString')
43
45
  if gmlLineString is None:
44
46
  logger.warning('No linearExtended/gmlLineString')
@@ -50,7 +52,7 @@ class GeoJSONGeometryTransformer(SituationRecordTransformer):
50
52
  }
51
53
  return geometry
52
54
 
53
- def _extract_point_geom(self, pointCoordinates: dict | None) -> dict | None:
55
+ def _extract_point_geom(self, pointCoordinates: JsonDict | None) -> JsonDict | None:
54
56
  if pointCoordinates is None:
55
57
  logger.warning('No pointCoordinates')
56
58
  return None
@@ -64,7 +66,7 @@ class GeoJSONGeometryTransformer(SituationRecordTransformer):
64
66
  }
65
67
  return geometry
66
68
 
67
- def _extract_multi_line_string(self, locationReference: dict) -> dict:
69
+ def _extract_multi_line_string(self, locationReference: JsonDict) -> JsonDict:
68
70
  locations = locationReference.get('locationContainedInGroup', {})
69
71
 
70
72
  lineStrings = []
@@ -82,7 +84,7 @@ class GeoJSONGeometryTransformer(SituationRecordTransformer):
82
84
 
83
85
  return {'type': 'MultiLineString', 'coordinates': lineStrings}
84
86
 
85
- def _extract_extendedLinear_geom(self, locationReference: dict) -> dict:
87
+ def _extract_extendedLinear_geom(self, locationReference: JsonDict) -> JsonDict:
86
88
  """
87
89
  Some publications use a custom extension extendedLinear to provide linear geometries using a verbose
88
90
  xml encoding.
@@ -119,7 +121,7 @@ class GeoJSONGeometryTransformer(SituationRecordTransformer):
119
121
 
120
122
  return {'type': 'LineString', 'coordinates': coordinates}
121
123
 
122
- def process_situation_record(self, situation_record: dict) -> None:
124
+ def process_situation_record(self, situation_record: JsonDict) -> None:
123
125
  locationReference = situation_record.get('locationReference')
124
126
  if locationReference is None:
125
127
  return
@@ -147,7 +149,7 @@ class GeoJSONGeometryTransformer(SituationRecordTransformer):
147
149
 
148
150
 
149
151
  class GeoJSONGeometryTransformer_DATEXII_3_7(GeoJSONGeometryTransformer):
150
- def __init__(self):
152
+ def __init__(self) -> None:
151
153
  super().__init__(
152
154
  'payload/sitSituationPublication/situation/situationRecord',
153
155
  'linearExtended',
@@ -155,5 +157,5 @@ class GeoJSONGeometryTransformer_DATEXII_3_7(GeoJSONGeometryTransformer):
155
157
 
156
158
 
157
159
  class GeoJSONGeometryTransformer_Simplified(GeoJSONGeometryTransformer):
158
- def __init__(self):
160
+ def __init__(self) -> None:
159
161
  super().__init__('payload/situation/situationRecord', None)