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.
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/PKG-INFO +9 -9
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/README.md +2 -2
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/pyproject.toml +53 -51
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/pyproject.toml.orig +16 -13
- datex2_xml2json-0.0.4/src/datex2_xml2json/_version.py +1 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/json_validator.py +6 -3
- datex2_xml2json-0.0.4/src/datex2_xml2json/py.typed +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/__init__.py +3 -2
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/base.py +17 -13
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/cifs_transformer.py +29 -24
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/geojson_geometry_transformer.py +10 -8
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/geoparquet_transformer.py +30 -14
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/jsonata_transformer.py +5 -3
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/roads_regio_transformer.py +8 -6
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/source_setter.py +5 -15
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/transformation_rules.py +23 -20
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transformer.py +62 -24
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/util.py +28 -13
- datex2_xml2json-0.0.1/src/datex2_xml2json/schema/Baustellen-4-00-00.sch +0 -7
- datex2_xml2json-0.0.1/src/datex2_xml2json/schema/DATEXII_3.7_Profile/.DS_Store +0 -0
- datex2_xml2json-0.0.1/src/datex2_xml2json/schema/DATEXII_3.7_Profile/xml/.DS_Store +0 -0
- datex2_xml2json-0.0.1/src/datex2_xml2json/transform/.DS_Store +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/LICENSE.md +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/__init__.py +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/merge.py +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXIISchema_2_2_0.xsd +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXIISchema_2_2_3.xsd +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_AfirEnergyInfrastructure.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_AfirFacilities.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Common.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_CommonExtension.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_ControlledZone.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_D2Payload.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_EnergyInfrastructure.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Facilities.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_FaultAndStatus.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_LocationExtension.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_LocationReferencing.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Parking.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_ReroutingManagementEnhanced.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_RoadTrafficData.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Situation.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_TrafficManagementPlan.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_TrafficRegulation.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_UrbanExtensions.json +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/DATEXII_3.7_Profile/DATEXII_3_Vms.json +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/MDM_BaustellenInfoDigitalRoadworksProfile_04-03-00.xsd +0 -0
- {datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/schema/MDM_Datenmodell_Baustellen_04-00-00.xsd +0 -0
- {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.
|
|
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
|
|
16
|
-
Requires-Dist: check-jsonschema>=0.38
|
|
17
|
-
Requires-Dist: jsonata-python>=0.7.0
|
|
18
|
-
Requires-Dist: geoparquet-io>=1.
|
|
19
|
-
Requires-Dist: pyarrow>=26
|
|
20
|
-
Requires-Dist: rs-xml2json
|
|
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
|
-
[
|
|
6
|
-
|
|
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
|
-
"
|
|
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
|
|
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
|
|
27
|
-
"check-jsonschema>=0.38
|
|
28
|
-
"jsonata-python>=0.7.0",
|
|
29
|
-
"geoparquet-io>=1.
|
|
30
|
-
"pyarrow>=26
|
|
31
|
-
"rs-xml2json
|
|
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
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
72
|
+
def process_situation_record(self, situation_record: JsonDict) -> None:
|
|
69
73
|
pass
|
|
70
74
|
|
|
71
|
-
def process(self, situation_record_wrapper:
|
|
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:
|
{datex2_xml2json-0.0.1 → datex2_xml2json-0.0.4}/src/datex2_xml2json/transform/cifs_transformer.py
RENAMED
|
@@ -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)?:"
|
|
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
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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 =
|
|
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
|
|
202
|
+
f' by {incident.get("type")} {incident.get("subtype")}'
|
|
198
203
|
)
|
|
199
204
|
highest_prio = current_prio
|
|
200
|
-
highest_prio_type = incident
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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)
|