polyxml 0.21.0__tar.gz → 0.22.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.
- {polyxml-0.21.0 → polyxml-0.22.0}/Cargo.lock +71 -5
- {polyxml-0.21.0 → polyxml-0.22.0}/Cargo.toml +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/PKG-INFO +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/benches/tag_dispatch.rs +4 -4
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/cpp/mod.rs +2 -2
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/csharp/mod.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/go/mod.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/java/mod.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/mod.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/python/mod.rs +3 -3
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/rust/mod.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/typescript/mod.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/json.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/parser.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/schema.rs +5 -5
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/schema_parser/mod.rs +26 -30
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/serializer.rs +3 -3
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_pattern_codegen.rs +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_python_codegen.rs +1 -1
- polyxml-0.21.0/crates/polyxml-core/tests/test_issue51_audit.rs → polyxml-0.22.0/crates/polyxml-core/tests/test_schema_audit.rs +25 -29
- polyxml-0.21.0/crates/polyxml-core/tests/test_issue53_xsi_type.rs → polyxml-0.22.0/crates/polyxml-core/tests/test_xsi_type.rs +8 -8
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/src/lib.rs +6 -6
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/tests/test_xsi_type.py +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/pyproject.toml +1 -1
- {polyxml-0.21.0 → polyxml-0.22.0}/README.md +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/python/polyxml/__init__.py +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.21.0 → polyxml-0.22.0}/python/polyxml/py.typed +0 -0
|
@@ -88,6 +88,12 @@ version = "2.13.2"
|
|
|
88
88
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
89
89
|
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
|
90
90
|
|
|
91
|
+
[[package]]
|
|
92
|
+
name = "bumpalo"
|
|
93
|
+
version = "3.20.3"
|
|
94
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
95
|
+
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
|
96
|
+
|
|
91
97
|
[[package]]
|
|
92
98
|
name = "cast"
|
|
93
99
|
version = "0.3.0"
|
|
@@ -602,7 +608,7 @@ dependencies = [
|
|
|
602
608
|
|
|
603
609
|
[[package]]
|
|
604
610
|
name = "polyxml"
|
|
605
|
-
version = "0.
|
|
611
|
+
version = "0.22.0"
|
|
606
612
|
dependencies = [
|
|
607
613
|
"criterion",
|
|
608
614
|
"heck",
|
|
@@ -622,14 +628,14 @@ dependencies = [
|
|
|
622
628
|
|
|
623
629
|
[[package]]
|
|
624
630
|
name = "polyxml-c"
|
|
625
|
-
version = "0.
|
|
631
|
+
version = "0.22.0"
|
|
626
632
|
dependencies = [
|
|
627
633
|
"polyxml",
|
|
628
634
|
]
|
|
629
635
|
|
|
630
636
|
[[package]]
|
|
631
637
|
name = "polyxml-cli"
|
|
632
|
-
version = "0.
|
|
638
|
+
version = "0.22.0"
|
|
633
639
|
dependencies = [
|
|
634
640
|
"clap",
|
|
635
641
|
"glob",
|
|
@@ -643,7 +649,7 @@ dependencies = [
|
|
|
643
649
|
|
|
644
650
|
[[package]]
|
|
645
651
|
name = "polyxml-js"
|
|
646
|
-
version = "0.
|
|
652
|
+
version = "0.22.0"
|
|
647
653
|
dependencies = [
|
|
648
654
|
"napi",
|
|
649
655
|
"napi-build",
|
|
@@ -653,7 +659,7 @@ dependencies = [
|
|
|
653
659
|
|
|
654
660
|
[[package]]
|
|
655
661
|
name = "polyxml-python"
|
|
656
|
-
version = "0.
|
|
662
|
+
version = "0.22.0"
|
|
657
663
|
dependencies = [
|
|
658
664
|
"lexical-core",
|
|
659
665
|
"polyxml",
|
|
@@ -661,6 +667,15 @@ dependencies = [
|
|
|
661
667
|
"smallvec",
|
|
662
668
|
]
|
|
663
669
|
|
|
670
|
+
[[package]]
|
|
671
|
+
name = "polyxml-wasm"
|
|
672
|
+
version = "0.22.0"
|
|
673
|
+
dependencies = [
|
|
674
|
+
"polyxml",
|
|
675
|
+
"quick-xml",
|
|
676
|
+
"wasm-bindgen",
|
|
677
|
+
]
|
|
678
|
+
|
|
664
679
|
[[package]]
|
|
665
680
|
name = "portable-atomic"
|
|
666
681
|
version = "1.15.0"
|
|
@@ -810,6 +825,12 @@ dependencies = [
|
|
|
810
825
|
"windows-sys",
|
|
811
826
|
]
|
|
812
827
|
|
|
828
|
+
[[package]]
|
|
829
|
+
name = "rustversion"
|
|
830
|
+
version = "1.0.23"
|
|
831
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
832
|
+
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
|
833
|
+
|
|
813
834
|
[[package]]
|
|
814
835
|
name = "same-file"
|
|
815
836
|
version = "1.0.6"
|
|
@@ -1041,6 +1062,51 @@ dependencies = [
|
|
|
1041
1062
|
"winapi-util",
|
|
1042
1063
|
]
|
|
1043
1064
|
|
|
1065
|
+
[[package]]
|
|
1066
|
+
name = "wasm-bindgen"
|
|
1067
|
+
version = "0.2.128"
|
|
1068
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1069
|
+
checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
|
|
1070
|
+
dependencies = [
|
|
1071
|
+
"cfg-if",
|
|
1072
|
+
"once_cell",
|
|
1073
|
+
"rustversion",
|
|
1074
|
+
"wasm-bindgen-macro",
|
|
1075
|
+
"wasm-bindgen-shared",
|
|
1076
|
+
]
|
|
1077
|
+
|
|
1078
|
+
[[package]]
|
|
1079
|
+
name = "wasm-bindgen-macro"
|
|
1080
|
+
version = "0.2.128"
|
|
1081
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1082
|
+
checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
|
|
1083
|
+
dependencies = [
|
|
1084
|
+
"quote",
|
|
1085
|
+
"wasm-bindgen-macro-support",
|
|
1086
|
+
]
|
|
1087
|
+
|
|
1088
|
+
[[package]]
|
|
1089
|
+
name = "wasm-bindgen-macro-support"
|
|
1090
|
+
version = "0.2.128"
|
|
1091
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1092
|
+
checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
|
|
1093
|
+
dependencies = [
|
|
1094
|
+
"bumpalo",
|
|
1095
|
+
"proc-macro2",
|
|
1096
|
+
"quote",
|
|
1097
|
+
"syn 3.0.5",
|
|
1098
|
+
"wasm-bindgen-shared",
|
|
1099
|
+
]
|
|
1100
|
+
|
|
1101
|
+
[[package]]
|
|
1102
|
+
name = "wasm-bindgen-shared"
|
|
1103
|
+
version = "0.2.128"
|
|
1104
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1105
|
+
checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
|
|
1106
|
+
dependencies = [
|
|
1107
|
+
"unicode-ident",
|
|
1108
|
+
]
|
|
1109
|
+
|
|
1044
1110
|
[[package]]
|
|
1045
1111
|
name = "winapi"
|
|
1046
1112
|
version = "0.3.9"
|
{polyxml-0.21.0 → polyxml-0.22.0}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// GENERATED by scripts/gen_tag_dispatch_fixtures.py — do not edit.
|
|
2
|
-
// Tag lists, string-match baselines, and phf tables for the
|
|
2
|
+
// Tag lists, string-match baselines, and phf tables for the
|
|
3
3
|
// tag_dispatch Criterion bench. Regenerate with:
|
|
4
4
|
// python3 scripts/gen_tag_dispatch_fixtures.py
|
|
5
5
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
//!
|
|
1
|
+
//! Tag-dispatch strategy comparison at schema scale tiers.
|
|
2
2
|
//!
|
|
3
|
-
//! Baselines
|
|
3
|
+
//! Baselines:
|
|
4
4
|
//! 1. Standard Rust `match` on string literals (LLVM bucketed memcmp chains)
|
|
5
5
|
//! 2. Runtime `HashMap<&str, u32>`
|
|
6
6
|
//! 3. Compile-time `phf::Map<&str, u32>`
|
|
7
7
|
//!
|
|
8
8
|
//! Each iteration sweeps the full tier (hit path for every tag); Criterion's
|
|
9
9
|
//! `Throughput::Elements` reports tags/second directly. Tokenization is
|
|
10
|
-
//! intentionally isolated OUT of the bench
|
|
11
|
-
//!
|
|
10
|
+
//! intentionally isolated OUT of the bench so lookup cost can be measured
|
|
11
|
+
//! independently of parsing (see
|
|
12
12
|
//! docs/benchmarks/rust-phf-dispatch.md).
|
|
13
13
|
//!
|
|
14
14
|
//! Regenerate the tag tables with scripts/gen_tag_dispatch_fixtures.py.
|
|
@@ -242,7 +242,7 @@ pub struct CppCodegen {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
/// Emitted C++ identifier for a named type, disambiguated across namespaces
|
|
245
|
-
/// for the IR currently being generated
|
|
245
|
+
/// for the IR currently being generated.
|
|
246
246
|
fn type_ident(q: &QName) -> String {
|
|
247
247
|
lookup_type_name(q, || to_cpp_type_name(&q.local))
|
|
248
248
|
}
|
|
@@ -704,7 +704,7 @@ concept XmlModel = requires(T a) {{
|
|
|
704
704
|
|
|
705
705
|
// from_string — stem follows the disambiguated type name only when
|
|
706
706
|
// it differs from the natural one, preserving the historical
|
|
707
|
-
// snake-of-local form otherwise
|
|
707
|
+
// snake-of-local form otherwise.
|
|
708
708
|
let natural = to_cpp_type_name(&enum_def.qname.local);
|
|
709
709
|
let stem = if enum_name == natural {
|
|
710
710
|
AsSnakeCase(&enum_def.qname.local).to_string()
|
|
@@ -234,7 +234,7 @@ pub struct CSharpCodegen {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
/// Emitted C# identifier for a named type, disambiguated across namespaces
|
|
237
|
-
/// for the IR currently being generated
|
|
237
|
+
/// for the IR currently being generated.
|
|
238
238
|
fn type_ident(q: &QName) -> String {
|
|
239
239
|
lookup_type_name(q, || to_csharp_type_name(&q.local))
|
|
240
240
|
}
|
|
@@ -234,7 +234,7 @@ pub struct GoCodegen {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
/// Emitted Go identifier for a named type, disambiguated across namespaces
|
|
237
|
-
/// for the IR currently being generated
|
|
237
|
+
/// for the IR currently being generated.
|
|
238
238
|
fn type_ident(q: &QName) -> String {
|
|
239
239
|
lookup_type_name(q, || to_go_type_name(&q.local))
|
|
240
240
|
}
|
|
@@ -208,7 +208,7 @@ pub fn to_java_type_name(name: &str) -> String {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
/// Emitted Java identifier for a named type, disambiguated across
|
|
211
|
-
/// namespaces for the IR currently being generated
|
|
211
|
+
/// namespaces for the IR currently being generated.
|
|
212
212
|
pub(super) fn type_ident(q: &QName) -> String {
|
|
213
213
|
lookup_type_name(q, || to_java_type_name(&q.local))
|
|
214
214
|
}
|
|
@@ -52,7 +52,7 @@ pub trait LanguageContext: Send + Sync {
|
|
|
52
52
|
|
|
53
53
|
thread_local! {
|
|
54
54
|
/// Disambiguated type identifiers for the IR currently being generated,
|
|
55
|
-
/// keyed by qualified name
|
|
55
|
+
/// keyed by qualified name. Refreshed at the start of
|
|
56
56
|
/// every `generate_module` call; lookups for names absent from the map
|
|
57
57
|
/// (e.g. references to unloaded external types) fall back to the
|
|
58
58
|
/// language's default local-name derivation.
|
|
@@ -15,7 +15,7 @@ use crate::ir::{
|
|
|
15
15
|
/// Module-level helper emitted when a simple type carries multiple pattern
|
|
16
16
|
/// facets: pydantic's `Field(pattern=...)` keeps only a single regex, so
|
|
17
17
|
/// AND-combined patterns are enforced through an `AfterValidator` wrapping
|
|
18
|
-
/// this factory instead
|
|
18
|
+
/// this factory instead.
|
|
19
19
|
const PATTERN_VALIDATOR_HELPER: &str = r#"def _polyxml_patterns(*patterns: str):
|
|
20
20
|
_compiled = tuple(re.compile(p) for p in patterns)
|
|
21
21
|
|
|
@@ -209,7 +209,7 @@ pub struct PythonCodegen {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
/// Emitted Python identifier for a named type, disambiguated across
|
|
212
|
-
/// namespaces for the IR currently being generated
|
|
212
|
+
/// namespaces for the IR currently being generated.
|
|
213
213
|
fn type_ident(q: &QName) -> String {
|
|
214
214
|
lookup_type_name(q, || AsPascalCase(&q.local).to_string())
|
|
215
215
|
}
|
|
@@ -570,7 +570,7 @@ impl PythonCodegen {
|
|
|
570
570
|
}
|
|
571
571
|
// Marks the type as a dispatch base: the runtime raises a clear
|
|
572
572
|
// error when xsi:type targets an abstract type with no registered
|
|
573
|
-
// derivations
|
|
573
|
+
// derivations.
|
|
574
574
|
if s.is_abstract {
|
|
575
575
|
out.push_str(" abstract = True\n");
|
|
576
576
|
}
|
|
@@ -202,7 +202,7 @@ pub struct RustCodegen {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
/// Emitted Rust identifier for a named type, disambiguated across
|
|
205
|
-
/// namespaces for the IR currently being generated
|
|
205
|
+
/// namespaces for the IR currently being generated.
|
|
206
206
|
fn type_ident(q: &QName) -> String {
|
|
207
207
|
lookup_type_name(q, || AsPascalCase(&q.local).to_string())
|
|
208
208
|
}
|
|
@@ -195,7 +195,7 @@ pub struct TypeScriptCodegen {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
/// Emitted TypeScript identifier for a named type, disambiguated across
|
|
198
|
-
/// namespaces for the IR currently being generated
|
|
198
|
+
/// namespaces for the IR currently being generated.
|
|
199
199
|
fn type_ident(q: &QName) -> String {
|
|
200
200
|
lookup_type_name(q, || to_ts_type_name(&q.local))
|
|
201
201
|
}
|
|
@@ -76,7 +76,7 @@ pub fn poly_value_to_json_value(
|
|
|
76
76
|
schema: &ModelSchema,
|
|
77
77
|
by_alias: bool,
|
|
78
78
|
) -> JsonValue {
|
|
79
|
-
// xsi:type dispatch
|
|
79
|
+
// xsi:type dispatch: a Record parsed as a concrete
|
|
80
80
|
// derivation iterates its own schema so variant-only fields survive
|
|
81
81
|
// transcoding (JSON carries no xsi:type marker).
|
|
82
82
|
let schema = match val {
|
|
@@ -144,7 +144,7 @@ fn xsi_type_value(e: &BytesStart, scope: &HashMap<String, String>) -> Result<Opt
|
|
|
144
144
|
Ok(None)
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
/// Resolve the concrete schema an element should be parsed with
|
|
147
|
+
/// Resolve the concrete schema an element should be parsed with.
|
|
148
148
|
///
|
|
149
149
|
/// When the declared type has `xsi:type` derivations registered (or is
|
|
150
150
|
/// abstract), the wire attribute selects one; unknown types on an abstract
|
|
@@ -80,7 +80,7 @@ pub struct ModelSchema {
|
|
|
80
80
|
pub element_map: HashMap<Vec<u8>, usize>,
|
|
81
81
|
pub attribute_map: HashMap<Vec<u8>, usize>,
|
|
82
82
|
pub text_field: Option<usize>,
|
|
83
|
-
/// Declared `abstract="true"` in the source schema
|
|
83
|
+
/// Declared `abstract="true"` in the source schema.
|
|
84
84
|
pub is_abstract: bool,
|
|
85
85
|
/// Concrete derivations eligible for `xsi:type` dispatch. Python may
|
|
86
86
|
/// refresh this registry when subclasses are defined after first use.
|
|
@@ -296,7 +296,7 @@ impl ModelSchema {
|
|
|
296
296
|
field_schema
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
/// Whether `d` transitively extends `base` via `xs:extension
|
|
299
|
+
/// Whether `d` transitively extends `base` via `xs:extension`.
|
|
300
300
|
fn derives_from(
|
|
301
301
|
ir: &crate::ir::SchemaIR,
|
|
302
302
|
d: &crate::ir::StructDef,
|
|
@@ -359,8 +359,8 @@ impl ModelSchema {
|
|
|
359
359
|
|
|
360
360
|
let schema = builder.build();
|
|
361
361
|
|
|
362
|
-
// xsi:type dispatch registry
|
|
363
|
-
// derivation of this type,
|
|
362
|
+
// xsi:type dispatch registry: every transitive
|
|
363
|
+
// derivation of this type, matched by namespace and local name.
|
|
364
364
|
let derived: Vec<crate::ir::QName> = ir
|
|
365
365
|
.types
|
|
366
366
|
.iter()
|
|
@@ -442,7 +442,7 @@ impl ModelSchemaBuilder {
|
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
-
/// Mark the type as `abstract="true"
|
|
445
|
+
/// Mark the type as `abstract="true"`.
|
|
446
446
|
pub fn is_abstract(mut self, is_abstract: bool) -> Self {
|
|
447
447
|
self.is_abstract = is_abstract;
|
|
448
448
|
self
|
|
@@ -49,15 +49,15 @@ struct PendingGroupRef {
|
|
|
49
49
|
/// A pure-Rust XSD 1.0/1.1 Schema Parser.
|
|
50
50
|
pub struct XsdParser {
|
|
51
51
|
/// Raw (pre-merge) IR per canonical file path, keyed so chameleon includes
|
|
52
|
-
/// can be re-namespaced per includer without re-parsing
|
|
52
|
+
/// can be re-namespaced per includer without re-parsing.
|
|
53
53
|
file_cache: HashMap<PathBuf, SchemaIR>,
|
|
54
54
|
/// Groups registered by each cached file, replayed on cache hits.
|
|
55
55
|
file_groups: HashMap<PathBuf, Vec<(QName, GroupDef)>>,
|
|
56
56
|
/// Files currently being parsed (include-cycle guard).
|
|
57
57
|
active_files: HashSet<PathBuf>,
|
|
58
|
-
/// Named model groups visible to the current parse
|
|
58
|
+
/// Named model groups visible to the current parse.
|
|
59
59
|
groups: HashMap<QName, GroupDef>,
|
|
60
|
-
/// Group references awaiting expansion at frame end
|
|
60
|
+
/// Group references awaiting expansion at frame end.
|
|
61
61
|
pending_group_refs: Vec<PendingGroupRef>,
|
|
62
62
|
/// Include/import recursion depth; post-passes run in every frame, the
|
|
63
63
|
/// root frame (depth 1 while executing) additionally drops dead refs.
|
|
@@ -149,9 +149,8 @@ impl XsdParser {
|
|
|
149
149
|
let mut ir = result?;
|
|
150
150
|
|
|
151
151
|
// Frame post-passes: inherit pattern facets up derivation chains
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
// so fields spliced in from groups are covered as well.
|
|
152
|
+
// and expand named model group references. Both are idempotent.
|
|
153
|
+
// Cycle detection runs last so fields spliced in from groups are covered.
|
|
155
154
|
inherit_pattern_facets(&mut ir);
|
|
156
155
|
self.expand_group_refs(&mut ir, self.frame_depth == 0);
|
|
157
156
|
ir.resolve_cycles();
|
|
@@ -223,7 +222,7 @@ impl XsdParser {
|
|
|
223
222
|
let mut sub_ir = self.parse_file(&inc_path)?;
|
|
224
223
|
// Chameleon include (no targetNamespace in the
|
|
225
224
|
// included file): attribute its components to
|
|
226
|
-
// this schema's namespace
|
|
225
|
+
// this schema's namespace.
|
|
227
226
|
if sub_ir.target_namespace.is_none() {
|
|
228
227
|
if let Some(ns) = target_namespace.as_deref() {
|
|
229
228
|
rekey_to_namespace(&mut sub_ir, ns);
|
|
@@ -285,7 +284,7 @@ impl XsdParser {
|
|
|
285
284
|
}
|
|
286
285
|
}
|
|
287
286
|
"group" => {
|
|
288
|
-
// Named model group definition
|
|
287
|
+
// Named model group definition.
|
|
289
288
|
if let Some(gname) = get_attr_value(e, "name") {
|
|
290
289
|
let gq = QName::new(target_namespace.as_deref(), gname);
|
|
291
290
|
let def = self.parse_group_body(
|
|
@@ -317,7 +316,7 @@ impl XsdParser {
|
|
|
317
316
|
let mut sub_ir = self.parse_file(&inc_path)?;
|
|
318
317
|
// Chameleon include (no targetNamespace in the
|
|
319
318
|
// included file): attribute its components to
|
|
320
|
-
// this schema's namespace
|
|
319
|
+
// this schema's namespace.
|
|
321
320
|
if sub_ir.target_namespace.is_none() {
|
|
322
321
|
if let Some(ns) = target_namespace.as_deref() {
|
|
323
322
|
rekey_to_namespace(&mut sub_ir, ns);
|
|
@@ -467,7 +466,7 @@ impl XsdParser {
|
|
|
467
466
|
base_type = Some(resolved);
|
|
468
467
|
}
|
|
469
468
|
// simpleContent extension: the text content is the
|
|
470
|
-
// value of the restricted base type
|
|
469
|
+
// value of the restricted base type.
|
|
471
470
|
if in_simple_content && !value_field_pushed {
|
|
472
471
|
value_field_pushed = true;
|
|
473
472
|
fields.push(value_field(&base, target_ns, prefixes));
|
|
@@ -516,8 +515,7 @@ impl XsdParser {
|
|
|
516
515
|
) {
|
|
517
516
|
// Consume inline type definitions so nested
|
|
518
517
|
// fields cannot leak into the parent struct;
|
|
519
|
-
// extracted types are registered in `ir
|
|
520
|
-
// (issue #51 item 5).
|
|
518
|
+
// extracted types are registered in `ir`.
|
|
521
519
|
self.consume_inline_element_type(
|
|
522
520
|
reader, e, target_ns, prefixes, &name, &mut field, ir,
|
|
523
521
|
)?;
|
|
@@ -621,7 +619,7 @@ impl XsdParser {
|
|
|
621
619
|
&& group_refs.is_empty()
|
|
622
620
|
&& fields.len() == choice_branches.len();
|
|
623
621
|
|
|
624
|
-
// Record group refs for post-parse expansion
|
|
622
|
+
// Record group refs for post-parse expansion.
|
|
625
623
|
if !is_union {
|
|
626
624
|
for (at, group) in group_refs {
|
|
627
625
|
self.pending_group_refs.push(PendingGroupRef {
|
|
@@ -653,7 +651,7 @@ impl XsdParser {
|
|
|
653
651
|
/// `complexType`/`simpleType` definition (and no `type`/`ref` attribute),
|
|
654
652
|
/// extract that definition as a uniquely named type and point `field` at
|
|
655
653
|
/// it. Otherwise the subtree is skipped so its content can never leak into
|
|
656
|
-
/// the enclosing struct
|
|
654
|
+
/// the enclosing struct.
|
|
657
655
|
#[allow(clippy::too_many_arguments)]
|
|
658
656
|
fn consume_inline_element_type(
|
|
659
657
|
&mut self,
|
|
@@ -731,7 +729,7 @@ impl XsdParser {
|
|
|
731
729
|
}
|
|
732
730
|
|
|
733
731
|
/// Parse the body of a named `<xs:group>` definition: its element
|
|
734
|
-
/// particles plus nested group references
|
|
732
|
+
/// particles plus nested group references.
|
|
735
733
|
fn parse_group_body(
|
|
736
734
|
&mut self,
|
|
737
735
|
reader: &mut Reader<&[u8]>,
|
|
@@ -967,7 +965,7 @@ impl XsdParser {
|
|
|
967
965
|
facets.patterns = vec![alternatives];
|
|
968
966
|
}
|
|
969
967
|
|
|
970
|
-
//
|
|
968
|
+
// Drop duplicate enumeration values (keep the first
|
|
971
969
|
// occurrence) and disambiguate variant names that collide after
|
|
972
970
|
// sanitization, so generated enums always compile.
|
|
973
971
|
if !enum_values.is_empty() {
|
|
@@ -1048,7 +1046,7 @@ impl XsdParser {
|
|
|
1048
1046
|
}
|
|
1049
1047
|
"complexType" => {
|
|
1050
1048
|
// Unique naming guards against `{name}Type`
|
|
1051
|
-
// colliding with an existing type
|
|
1049
|
+
// colliding with an existing type.
|
|
1052
1050
|
let anon_name =
|
|
1053
1051
|
unique_type_name(ir, target_ns, &format!("{}Type", name));
|
|
1054
1052
|
let anon_qname = QName::new(target_ns, anon_name.clone());
|
|
@@ -1122,9 +1120,9 @@ impl XsdParser {
|
|
|
1122
1120
|
}))
|
|
1123
1121
|
}
|
|
1124
1122
|
|
|
1125
|
-
/// Splice referenced group fields into their owner structs
|
|
1126
|
-
///
|
|
1127
|
-
///
|
|
1123
|
+
/// Splice referenced group fields into their owner structs. Runs at the
|
|
1124
|
+
/// end of every parse frame; entries that cannot be resolved yet are
|
|
1125
|
+
/// carried to the parent frame (dropped at the root).
|
|
1128
1126
|
fn expand_group_refs(&mut self, ir: &mut SchemaIR, root: bool) {
|
|
1129
1127
|
let pending = std::mem::take(&mut self.pending_group_refs);
|
|
1130
1128
|
let mut carried: Vec<PendingGroupRef> = Vec::new();
|
|
@@ -1184,9 +1182,9 @@ impl XsdParser {
|
|
|
1184
1182
|
Some(fields)
|
|
1185
1183
|
}
|
|
1186
1184
|
|
|
1187
|
-
/// Re-namespace parser state created during a chameleon include
|
|
1188
|
-
///
|
|
1189
|
-
///
|
|
1185
|
+
/// Re-namespace parser state created during a chameleon include: newly
|
|
1186
|
+
/// registered groups and carried group refs that still carry no namespace
|
|
1187
|
+
/// adopt the includer's namespace.
|
|
1190
1188
|
fn rekey_new_state(&mut self, groups_before: &HashSet<QName>, pend_before: usize, ns: &str) {
|
|
1191
1189
|
let stale: Vec<QName> = self
|
|
1192
1190
|
.groups
|
|
@@ -1455,8 +1453,7 @@ fn skip_subtree(reader: &mut Reader<&[u8]>) -> Result<(), SchemaError> {
|
|
|
1455
1453
|
Ok(())
|
|
1456
1454
|
}
|
|
1457
1455
|
|
|
1458
|
-
/// The synthetic `<Text>` field representing a `simpleContent` value
|
|
1459
|
-
/// (issue #51 item 4).
|
|
1456
|
+
/// The synthetic `<Text>` field representing a `simpleContent` value.
|
|
1460
1457
|
fn value_field(
|
|
1461
1458
|
base: &str,
|
|
1462
1459
|
target_ns: Option<&str>,
|
|
@@ -1478,8 +1475,8 @@ fn value_field(
|
|
|
1478
1475
|
}
|
|
1479
1476
|
}
|
|
1480
1477
|
|
|
1481
|
-
/// Pick a type name that does not collide with an existing type in `ir
|
|
1482
|
-
///
|
|
1478
|
+
/// Pick a type name that does not collide with an existing type in `ir`:
|
|
1479
|
+
/// `{base}`, `{base}2`, `{base}3`, ...
|
|
1483
1480
|
fn unique_type_name(ir: &SchemaIR, target_ns: Option<&str>, base: &str) -> String {
|
|
1484
1481
|
let mut name = base.to_string();
|
|
1485
1482
|
let mut n = 2u32;
|
|
@@ -1491,8 +1488,7 @@ fn unique_type_name(ir: &SchemaIR, target_ns: Option<&str>, base: &str) -> Strin
|
|
|
1491
1488
|
}
|
|
1492
1489
|
|
|
1493
1490
|
/// Rewrite every namespace-less QName in the IR to `ns`. Used for chameleon
|
|
1494
|
-
/// includes, whose components adopt the including schema's target namespace
|
|
1495
|
-
/// (issue #51 item 9).
|
|
1491
|
+
/// includes, whose components adopt the including schema's target namespace.
|
|
1496
1492
|
fn rekey_to_namespace(ir: &mut SchemaIR, ns: &str) {
|
|
1497
1493
|
ir.target_namespace = Some(ns.to_string());
|
|
1498
1494
|
|
|
@@ -1625,7 +1621,7 @@ fn rekey_group_def(def: &mut GroupDef, ns: &str) {
|
|
|
1625
1621
|
}
|
|
1626
1622
|
|
|
1627
1623
|
/// Inherit pattern facets from base simple types down their derivation
|
|
1628
|
-
/// chains
|
|
1624
|
+
/// chains: every derivation step's patterns must be
|
|
1629
1625
|
/// enforced together. Idempotent.
|
|
1630
1626
|
fn inherit_pattern_facets(ir: &mut SchemaIR) {
|
|
1631
1627
|
let derived: Vec<(QName, QName)> = ir
|
|
@@ -107,7 +107,7 @@ impl NamespaceContext {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
// xsi:type dispatch
|
|
110
|
+
// xsi:type dispatch: variant namespaces must be in
|
|
111
111
|
// scope, and the XML Schema Instance namespace is required to
|
|
112
112
|
// write the xsi:type selector itself.
|
|
113
113
|
let variants = schema.variants();
|
|
@@ -237,7 +237,7 @@ impl XmlSerializer {
|
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
// xsi:type dispatch
|
|
240
|
+
// xsi:type dispatch: when the value is a Record built
|
|
241
241
|
// from a registered derivation of the declared schema, write the
|
|
242
242
|
// concrete variant's fields and re-emit the xsi:type selector.
|
|
243
243
|
let mut xsi_type: Option<String> = None;
|
|
@@ -312,7 +312,7 @@ impl XmlSerializer {
|
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
// Re-emit the xsi:type selector after content attributes
|
|
315
|
+
// Re-emit the xsi:type selector after content attributes.
|
|
316
316
|
if let Some(ref xsi_val) = xsi_type {
|
|
317
317
|
let attr_key = match ns_ctx {
|
|
318
318
|
Some(ctx) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//!
|
|
1
|
+
//! Execute generated validators, not just regex source assertions.
|
|
2
2
|
use polyxml::codegen::*;
|
|
3
3
|
use polyxml::ir::{QName, RestrictionFacets, SchemaIR, TypeDef};
|
|
4
4
|
use polyxml::schema_parser::XsdParser;
|
|
@@ -437,7 +437,7 @@ fn test_python_generated_tag_and_custom_header() {
|
|
|
437
437
|
|
|
438
438
|
#[test]
|
|
439
439
|
fn test_python_abstract_meta_emission() {
|
|
440
|
-
//
|
|
440
|
+
// Abstract complex types mark Meta.abstract so the runtime
|
|
441
441
|
// can raise a clear error for xsi:type values with no derivations.
|
|
442
442
|
let mut ir = SchemaIR::new().with_target_namespace("urn:veh");
|
|
443
443
|
ir.add_type(TypeDef::Struct(StructDef {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
//!
|
|
1
|
+
//! Regression tests for edge-case XSD parsing and code generation.
|
|
2
2
|
//!
|
|
3
|
-
//!
|
|
4
|
-
//!
|
|
5
|
-
//! passing tests lock in behavior audited as already correct.
|
|
3
|
+
//! These tests cover named groups, duplicate enum values, nested inline
|
|
4
|
+
//! types, namespace collisions, simple content, and include behavior.
|
|
6
5
|
|
|
7
6
|
use std::collections::HashSet;
|
|
8
7
|
use std::fs;
|
|
@@ -40,11 +39,11 @@ fn field_names(s: &StructDef) -> Vec<String> {
|
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
// ---------------------------------------------------------------------------
|
|
43
|
-
//
|
|
42
|
+
// xs:group named model groups
|
|
44
43
|
// ---------------------------------------------------------------------------
|
|
45
44
|
|
|
46
45
|
#[test]
|
|
47
|
-
fn
|
|
46
|
+
fn named_group_reference_fields_are_parsed() {
|
|
48
47
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
49
48
|
targetNamespace="urn:g" xmlns:t="urn:g" elementFormDefault="qualified">
|
|
50
49
|
<xs:group name="HeaderParts">
|
|
@@ -74,11 +73,11 @@ fn issue51_item1_named_group_reference_fields_are_parsed() {
|
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
// ---------------------------------------------------------------------------
|
|
77
|
-
//
|
|
76
|
+
// duplicate enum variant deduplication
|
|
78
77
|
// ---------------------------------------------------------------------------
|
|
79
78
|
|
|
80
79
|
#[test]
|
|
81
|
-
fn
|
|
80
|
+
fn duplicate_enumeration_values_are_deduped() {
|
|
82
81
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
83
82
|
targetNamespace="urn:e" elementFormDefault="qualified">
|
|
84
83
|
<xs:simpleType name="SettlementStatus">
|
|
@@ -104,7 +103,7 @@ fn issue51_item2_duplicate_enumeration_values_are_deduped() {
|
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
#[test]
|
|
107
|
-
fn
|
|
106
|
+
fn distinct_values_with_colliding_variant_names_stay_unique() {
|
|
108
107
|
// "failed" and "Failed" are distinct (legal) XSD values but sanitize to the
|
|
109
108
|
// same variant identifier in every target language.
|
|
110
109
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
@@ -140,7 +139,7 @@ fn issue51_item2_distinct_values_with_colliding_variant_names_stay_unique() {
|
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
// ---------------------------------------------------------------------------
|
|
143
|
-
//
|
|
142
|
+
// cross-namespace same-local-name collision in flat output
|
|
144
143
|
// ---------------------------------------------------------------------------
|
|
145
144
|
|
|
146
145
|
fn two_namespace_address_ir() -> SchemaIR {
|
|
@@ -184,7 +183,7 @@ fn declared_prefixed_idents(code: &str, markers: &[&str], prefix: &str) -> HashS
|
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
#[test]
|
|
187
|
-
fn
|
|
186
|
+
fn rust_flat_output_has_no_colliding_type_names() {
|
|
188
187
|
let ir = two_namespace_address_ir();
|
|
189
188
|
let code = RustCodegen::new(RustOptions::default()).generate_module(&ir);
|
|
190
189
|
|
|
@@ -218,7 +217,7 @@ fn issue51_item3_rust_flat_output_has_no_colliding_type_names() {
|
|
|
218
217
|
}
|
|
219
218
|
|
|
220
219
|
#[test]
|
|
221
|
-
fn
|
|
220
|
+
fn all_languages_disambiguate_flat_collision() {
|
|
222
221
|
let ir = two_namespace_address_ir();
|
|
223
222
|
let outputs = [
|
|
224
223
|
(
|
|
@@ -266,11 +265,11 @@ fn issue51_item3_all_languages_disambiguate_flat_collision() {
|
|
|
266
265
|
}
|
|
267
266
|
|
|
268
267
|
// ---------------------------------------------------------------------------
|
|
269
|
-
//
|
|
268
|
+
// simpleContent extension text field
|
|
270
269
|
// ---------------------------------------------------------------------------
|
|
271
270
|
|
|
272
271
|
#[test]
|
|
273
|
-
fn
|
|
272
|
+
fn simple_content_extension_emits_value_field() {
|
|
274
273
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
275
274
|
targetNamespace="urn:amt" elementFormDefault="qualified">
|
|
276
275
|
<xs:complexType name="AmountWithCurrency">
|
|
@@ -307,11 +306,11 @@ fn issue51_item4_simple_content_extension_emits_value_field() {
|
|
|
307
306
|
}
|
|
308
307
|
|
|
309
308
|
// ---------------------------------------------------------------------------
|
|
310
|
-
//
|
|
309
|
+
// anonymous inline complexType extraction (nested)
|
|
311
310
|
// ---------------------------------------------------------------------------
|
|
312
311
|
|
|
313
312
|
#[test]
|
|
314
|
-
fn
|
|
313
|
+
fn nested_inline_complex_type_is_extracted_not_leaked() {
|
|
315
314
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
316
315
|
targetNamespace="urn:ord" elementFormDefault="qualified">
|
|
317
316
|
<xs:complexType name="Order">
|
|
@@ -356,11 +355,11 @@ fn issue51_item5_nested_inline_complex_type_is_extracted_not_leaked() {
|
|
|
356
355
|
}
|
|
357
356
|
|
|
358
357
|
// ---------------------------------------------------------------------------
|
|
359
|
-
//
|
|
358
|
+
// unknown element tolerance in generated serde codecs
|
|
360
359
|
// ---------------------------------------------------------------------------
|
|
361
360
|
|
|
362
361
|
#[test]
|
|
363
|
-
fn
|
|
362
|
+
fn generated_rust_has_no_deny_unknown_fields() {
|
|
364
363
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
365
364
|
targetNamespace="urn:p" elementFormDefault="qualified">
|
|
366
365
|
<xs:complexType name="Person">
|
|
@@ -379,7 +378,7 @@ fn issue51_item6_generated_rust_has_no_deny_unknown_fields() {
|
|
|
379
378
|
}
|
|
380
379
|
|
|
381
380
|
#[test]
|
|
382
|
-
fn
|
|
381
|
+
fn quick_xml_serde_skips_unknown_elements() {
|
|
383
382
|
// Mirrors the derive set emitted by the Rust codegen; verifies quick-xml's
|
|
384
383
|
// default Deserialize behavior skips elements not present on the struct.
|
|
385
384
|
#[derive(Debug, serde::Deserialize)]
|
|
@@ -393,17 +392,14 @@ fn issue51_item6_quick_xml_serde_skips_unknown_elements() {
|
|
|
393
392
|
assert_eq!(parsed.name, "Alex");
|
|
394
393
|
}
|
|
395
394
|
|
|
396
|
-
//
|
|
397
|
-
// Item 7: xsi:type polymorphic dispatch — implemented as issue #53;
|
|
398
|
-
// see `tests/test_issue53_xsi_type.rs`.
|
|
399
|
-
// ---------------------------------------------------------------------------
|
|
395
|
+
// `xsi:type` polymorphic dispatch is covered in `tests/test_xsi_type.rs`.
|
|
400
396
|
|
|
401
397
|
// ---------------------------------------------------------------------------
|
|
402
|
-
//
|
|
398
|
+
// pattern facet AND/OR derivation semantics
|
|
403
399
|
// ---------------------------------------------------------------------------
|
|
404
400
|
|
|
405
401
|
#[test]
|
|
406
|
-
fn
|
|
402
|
+
fn derived_simple_type_inherits_base_patterns() {
|
|
407
403
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
408
404
|
targetNamespace="urn:pat" xmlns:t="urn:pat" elementFormDefault="qualified">
|
|
409
405
|
<xs:simpleType name="BaseCode">
|
|
@@ -459,11 +455,11 @@ fn issue51_item8_derived_simple_type_inherits_base_patterns() {
|
|
|
459
455
|
}
|
|
460
456
|
|
|
461
457
|
// ---------------------------------------------------------------------------
|
|
462
|
-
//
|
|
458
|
+
// include cache / chameleon namespace attribution
|
|
463
459
|
// ---------------------------------------------------------------------------
|
|
464
460
|
|
|
465
461
|
#[test]
|
|
466
|
-
fn
|
|
462
|
+
fn chameleon_include_adopts_including_namespace_per_includer() {
|
|
467
463
|
let dir = tempdir().expect("tempdir");
|
|
468
464
|
let common = dir.path().join("common.xsd");
|
|
469
465
|
fs::write(
|
|
@@ -530,11 +526,11 @@ fn issue51_item9_chameleon_include_adopts_including_namespace_per_includer() {
|
|
|
530
526
|
}
|
|
531
527
|
|
|
532
528
|
// ---------------------------------------------------------------------------
|
|
533
|
-
//
|
|
529
|
+
// named aliases/newtypes for restricted simple types
|
|
534
530
|
// ---------------------------------------------------------------------------
|
|
535
531
|
|
|
536
532
|
#[test]
|
|
537
|
-
fn
|
|
533
|
+
fn restricted_simple_types_emit_named_aliases() {
|
|
538
534
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
539
535
|
targetNamespace="urn:bic" elementFormDefault="qualified">
|
|
540
536
|
<xs:simpleType name="BicCode">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//!
|
|
1
|
+
//! `xsi:type` polymorphic dispatch for abstract complex types.
|
|
2
2
|
//!
|
|
3
3
|
//! Locks in the runtime registry strategy: `ModelSchema` carries the
|
|
4
4
|
//! concrete derivations of a type (keyed by QName local part), the parser
|
|
@@ -97,7 +97,7 @@ fn schema_local(schema: &ModelSchema) -> String {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
#[test]
|
|
100
|
-
fn
|
|
100
|
+
fn from_ir_flattens_base_fields_and_registers_variants() {
|
|
101
101
|
let root = schema_for(Some("Root"));
|
|
102
102
|
let declared = declared_vehicle(&root);
|
|
103
103
|
|
|
@@ -133,7 +133,7 @@ fn issue53_from_ir_flattens_base_fields_and_registers_variants() {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
#[test]
|
|
136
|
-
fn
|
|
136
|
+
fn nested_xsi_type_dispatch_and_round_trip() {
|
|
137
137
|
let root = schema_for(Some("Root"));
|
|
138
138
|
let xml = br#"<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="urn:veh">
|
|
139
139
|
<vehicle xsi:type="t:Car"><id>V1</id><doors>4</doors></vehicle>
|
|
@@ -188,7 +188,7 @@ fn issue53_nested_xsi_type_dispatch_and_round_trip() {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
#[test]
|
|
191
|
-
fn
|
|
191
|
+
fn root_xsi_type_dispatch_including_empty_element() {
|
|
192
192
|
let root = schema_for(Some("Vehicle"));
|
|
193
193
|
assert!(root.is_abstract);
|
|
194
194
|
assert!(root.has_variants());
|
|
@@ -220,7 +220,7 @@ fn issue53_root_xsi_type_dispatch_including_empty_element() {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
#[test]
|
|
223
|
-
fn
|
|
223
|
+
fn unknown_xsi_type_on_abstract_type_errors() {
|
|
224
224
|
let root = schema_for(Some("Root"));
|
|
225
225
|
let xml = br#"<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="urn:veh"><vehicle xsi:type="t:Plane"><id>X</id></vehicle></Root>"#;
|
|
226
226
|
let err = polyxml::deserialize(xml, root).expect_err("unknown derivation must fail");
|
|
@@ -236,7 +236,7 @@ fn issue53_unknown_xsi_type_on_abstract_type_errors() {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
#[test]
|
|
239
|
-
fn
|
|
239
|
+
fn abstract_type_without_derivations_errors() {
|
|
240
240
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
241
241
|
targetNamespace="urn:solo" xmlns:t="urn:solo">
|
|
242
242
|
<xs:complexType name="Solo" abstract="true">
|
|
@@ -261,7 +261,7 @@ fn issue53_abstract_type_without_derivations_errors() {
|
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
#[test]
|
|
264
|
-
fn
|
|
264
|
+
fn plain_type_attribute_is_not_mistaken_for_dispatch() {
|
|
265
265
|
// A content attribute literally named "type" on a non-abstract type
|
|
266
266
|
// must never be treated as an xsi:type selector.
|
|
267
267
|
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
@@ -292,7 +292,7 @@ fn issue53_plain_type_attribute_is_not_mistaken_for_dispatch() {
|
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
#[test]
|
|
295
|
-
fn
|
|
295
|
+
fn iterparse_dispatches_each_streamed_item() {
|
|
296
296
|
let root = schema_for(Some("Root"));
|
|
297
297
|
let declared = declared_vehicle(&root);
|
|
298
298
|
let xml = br#"<wrap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="urn:veh">
|
|
@@ -269,7 +269,7 @@ fn extract_schema_from_class<'py>(
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
|
-
//
|
|
272
|
+
// Abstract types raise a clear error when xsi:type names
|
|
273
273
|
// a derivation the runtime does not know.
|
|
274
274
|
if let Ok(abstract_val) = meta_cls.getattr("abstract") {
|
|
275
275
|
if abstract_val.extract::<bool>().unwrap_or(false) {
|
|
@@ -483,7 +483,7 @@ fn get_or_create_schema_meta<'py>(cls: &Bound<'py, PyType>) -> PyResult<Arc<Cach
|
|
|
483
483
|
map.insert(schema.name.clone(), Arc::clone(&meta));
|
|
484
484
|
}
|
|
485
485
|
|
|
486
|
-
// xsi:type dispatch
|
|
486
|
+
// xsi:type dispatch: register concrete subclasses as
|
|
487
487
|
// derivations of this type. Deliberately runs AFTER the cache inserts so
|
|
488
488
|
// a subclass field typed as this class resolves from cache instead of
|
|
489
489
|
// re-entering extraction.
|
|
@@ -493,7 +493,7 @@ fn get_or_create_schema_meta<'py>(cls: &Bound<'py, PyType>) -> PyResult<Arc<Cach
|
|
|
493
493
|
}
|
|
494
494
|
|
|
495
495
|
/// Collect runtime schemas for every dataclass/Pydantic subclass of `cls`,
|
|
496
|
-
/// transitively, to power `xsi:type` dispatch
|
|
496
|
+
/// transitively, to power `xsi:type` dispatch.
|
|
497
497
|
fn discover_variants(cls: &Bound<'_, PyType>) -> Vec<Arc<ModelSchema>> {
|
|
498
498
|
let mut out = Vec::new();
|
|
499
499
|
let mut seen: HashSet<usize> = HashSet::new();
|
|
@@ -677,7 +677,7 @@ fn poly_value_to_py<'py>(
|
|
|
677
677
|
schema: rec_schema,
|
|
678
678
|
values,
|
|
679
679
|
} => {
|
|
680
|
-
// xsi:type dispatch
|
|
680
|
+
// xsi:type dispatch: the record was parsed as a
|
|
681
681
|
// concrete derivation of the declared type, so construct it with
|
|
682
682
|
// the derivation's Python class.
|
|
683
683
|
if let ValueType::Nested(ref declared) = val_type {
|
|
@@ -964,7 +964,7 @@ fn py_to_poly_value<'py>(
|
|
|
964
964
|
meta_opt: Option<&CachedSchemaMeta>,
|
|
965
965
|
) -> PyResult<PolyValue> {
|
|
966
966
|
if let Some(meta) = meta_opt {
|
|
967
|
-
// xsi:type dispatch
|
|
967
|
+
// xsi:type dispatch: a concrete subclass instance in a
|
|
968
968
|
// field declared as the base type builds the derivation's record so
|
|
969
969
|
// the serializer re-emits xsi:type and keeps every concrete field.
|
|
970
970
|
let obj_type = obj.get_type();
|
|
@@ -1231,7 +1231,7 @@ fn serialize<'py>(
|
|
|
1231
1231
|
ns_map: Option<Bound<'py, PyDict>>,
|
|
1232
1232
|
) -> PyResult<Bound<'py, PyBytes>> {
|
|
1233
1233
|
// With `target_type`, serialize against the declared base type so
|
|
1234
|
-
// xsi:type dispatch round-trips the element name
|
|
1234
|
+
// xsi:type dispatch round-trips the element name; without
|
|
1235
1235
|
// it, the instance's own concrete type is used.
|
|
1236
1236
|
let meta = match &target_type {
|
|
1237
1237
|
Some(t) => get_or_create_schema_meta(t)?,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""xsi:type polymorphic dispatch through the Python runtime.
|
|
2
2
|
|
|
3
3
|
Covers both directions: parsing wire xsi:type selectors into concrete
|
|
4
4
|
subclasses (discovered from the Python class hierarchy), and re-emitting
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|