polyxml 0.34.2__tar.gz → 0.34.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.
- {polyxml-0.34.2 → polyxml-0.34.4}/Cargo.lock +6 -6
- {polyxml-0.34.2 → polyxml-0.34.4}/Cargo.toml +1 -1
- {polyxml-0.34.2 → polyxml-0.34.4}/PKG-INFO +1 -1
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/csharp/mod.rs +100 -1
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/rust/mod.rs +78 -8
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/schema_parser/mod.rs +88 -25
- polyxml-0.34.4/crates/polyxml-core/tests/test_qualified_attributes.rs +170 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_rust_codegen.rs +60 -1
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_schema_ir.rs +137 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/pyproject.toml +1 -1
- polyxml-0.34.2/crates/polyxml-core/tests/test_qualified_attributes.rs +0 -80
- {polyxml-0.34.2 → polyxml-0.34.4}/README.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/integer.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/ir/chunker.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/ir/particle.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/parser.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/schema.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/schema_parser/upa.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/serializer.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_any_attribute.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_any_element.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_lexical_lists.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_temporal_union.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_ubl_csharp.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_upa.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_value_constraints.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/src/lib.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/python/polyxml/__init__.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.4}/python/polyxml/py.typed +0 -0
|
@@ -608,7 +608,7 @@ dependencies = [
|
|
|
608
608
|
|
|
609
609
|
[[package]]
|
|
610
610
|
name = "polyxml"
|
|
611
|
-
version = "0.34.
|
|
611
|
+
version = "0.34.4"
|
|
612
612
|
dependencies = [
|
|
613
613
|
"criterion",
|
|
614
614
|
"heck",
|
|
@@ -629,14 +629,14 @@ dependencies = [
|
|
|
629
629
|
|
|
630
630
|
[[package]]
|
|
631
631
|
name = "polyxml-c"
|
|
632
|
-
version = "0.34.
|
|
632
|
+
version = "0.34.4"
|
|
633
633
|
dependencies = [
|
|
634
634
|
"polyxml",
|
|
635
635
|
]
|
|
636
636
|
|
|
637
637
|
[[package]]
|
|
638
638
|
name = "polyxml-cli"
|
|
639
|
-
version = "0.34.
|
|
639
|
+
version = "0.34.4"
|
|
640
640
|
dependencies = [
|
|
641
641
|
"clap",
|
|
642
642
|
"glob",
|
|
@@ -650,7 +650,7 @@ dependencies = [
|
|
|
650
650
|
|
|
651
651
|
[[package]]
|
|
652
652
|
name = "polyxml-js"
|
|
653
|
-
version = "0.34.
|
|
653
|
+
version = "0.34.4"
|
|
654
654
|
dependencies = [
|
|
655
655
|
"napi",
|
|
656
656
|
"napi-build",
|
|
@@ -660,7 +660,7 @@ dependencies = [
|
|
|
660
660
|
|
|
661
661
|
[[package]]
|
|
662
662
|
name = "polyxml-python"
|
|
663
|
-
version = "0.34.
|
|
663
|
+
version = "0.34.4"
|
|
664
664
|
dependencies = [
|
|
665
665
|
"lexical-core",
|
|
666
666
|
"polyxml",
|
|
@@ -670,7 +670,7 @@ dependencies = [
|
|
|
670
670
|
|
|
671
671
|
[[package]]
|
|
672
672
|
name = "polyxml-wasm"
|
|
673
|
-
version = "0.34.
|
|
673
|
+
version = "0.34.4"
|
|
674
674
|
dependencies = [
|
|
675
675
|
"polyxml",
|
|
676
676
|
"quick-xml",
|
|
@@ -1099,6 +1099,53 @@ impl CSharpCodegen {
|
|
|
1099
1099
|
true
|
|
1100
1100
|
}
|
|
1101
1101
|
|
|
1102
|
+
fn emit_optional_enum_attribute_proxy(
|
|
1103
|
+
&self,
|
|
1104
|
+
out: &mut String,
|
|
1105
|
+
field: &FieldDef,
|
|
1106
|
+
name: &str,
|
|
1107
|
+
ir: &SchemaIR,
|
|
1108
|
+
indent: &str,
|
|
1109
|
+
) -> bool {
|
|
1110
|
+
if !self.options.emit_xml_attributes
|
|
1111
|
+
|| field.kind != FieldKind::Attribute
|
|
1112
|
+
|| !field.cardinality.is_optional()
|
|
1113
|
+
|| field.cardinality.is_list()
|
|
1114
|
+
{
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
let TypeRef::Named(qname) = &field.type_ref else {
|
|
1118
|
+
return false;
|
|
1119
|
+
};
|
|
1120
|
+
if !matches!(ir.types.get(qname), Some(TypeDef::Enum(_))) {
|
|
1121
|
+
return false;
|
|
1122
|
+
}
|
|
1123
|
+
let ty = self.map_field_type(field, ir);
|
|
1124
|
+
let base = ty.trim_end_matches('?');
|
|
1125
|
+
let namespace = field
|
|
1126
|
+
.namespace
|
|
1127
|
+
.as_ref()
|
|
1128
|
+
.map(|ns| format!(", Namespace = {ns:?}"))
|
|
1129
|
+
.unwrap_or_default();
|
|
1130
|
+
if self.options.emit_json_attributes {
|
|
1131
|
+
writeln!(out, "{indent} [JsonPropertyName({:?})]", field.xml_name).unwrap();
|
|
1132
|
+
}
|
|
1133
|
+
writeln!(
|
|
1134
|
+
out,
|
|
1135
|
+
"{indent} [XmlIgnore] public {ty} {name} {{ get; set; }}"
|
|
1136
|
+
)
|
|
1137
|
+
.unwrap();
|
|
1138
|
+
if self.options.emit_json_attributes {
|
|
1139
|
+
// Keep the XML lexical proxy out of JSON, preserving the typed property.
|
|
1140
|
+
writeln!(out, "{indent} [JsonIgnore]").unwrap();
|
|
1141
|
+
}
|
|
1142
|
+
writeln!(out, "{indent} [XmlAttribute({:?}{namespace})] public string? {name}Xml {{
|
|
1143
|
+
{indent} get => {name}?.ToXmlValue();
|
|
1144
|
+
{indent} set => {name} = value is null ? null : ({base})new XmlSerializer(typeof({base}), new XmlRootAttribute(\"value\")).Deserialize(new System.IO.StringReader(\"<value>\" + System.Security.SecurityElement.Escape(value) + \"</value>\"))!;
|
|
1145
|
+
{indent} }}", field.xml_name).unwrap();
|
|
1146
|
+
true
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1102
1149
|
fn emit_default_scalar_proxy(
|
|
1103
1150
|
&self,
|
|
1104
1151
|
out: &mut String,
|
|
@@ -1379,7 +1426,10 @@ impl CSharpCodegen {
|
|
|
1379
1426
|
format!(" : {}", base_clause.join(", "))
|
|
1380
1427
|
};
|
|
1381
1428
|
|
|
1382
|
-
|
|
1429
|
+
// Reserve the actual generated names on every ancestor. Distinct
|
|
1430
|
+
// XML members (e.g. nameOfClass attribute and NameOfClass element)
|
|
1431
|
+
// can normalize to the same C# identifier.
|
|
1432
|
+
let mut seen_props = self.inherited_property_names(s, ir, &mut HashSet::new());
|
|
1383
1433
|
let prop_names: Vec<String> = s
|
|
1384
1434
|
.fields
|
|
1385
1435
|
.iter()
|
|
@@ -1392,6 +1442,8 @@ impl CSharpCodegen {
|
|
|
1392
1442
|
}
|
|
1393
1443
|
|
|
1394
1444
|
let has_lexical_union = self.options.emit_xml_attributes && s.fields.iter().any(|f| {
|
|
1445
|
+
(f.kind == FieldKind::Attribute && f.cardinality.is_optional()
|
|
1446
|
+
&& matches!(&f.type_ref, TypeRef::Named(q) if matches!(ir.types.get(q), Some(TypeDef::Enum(_))))) ||
|
|
1395
1447
|
matches!(f.type_ref, TypeRef::Primitive(p) if p.is_unbounded_integer()) || matches!(f.type_ref, TypeRef::Primitive(PrimitiveType::Date | PrimitiveType::DateTime | PrimitiveType::Time | PrimitiveType::Duration)) || f.default_value.is_some() || f.fixed_value.is_some() || matches!(&f.type_ref, TypeRef::Named(q) if matches!(ir.types.get(q), Some(TypeDef::Union(u)) if u.is_lexical()))
|
|
1396
1448
|
});
|
|
1397
1449
|
|
|
@@ -1404,6 +1456,7 @@ impl CSharpCodegen {
|
|
|
1404
1456
|
.unwrap();
|
|
1405
1457
|
for (f, name) in s.fields.iter().zip(&prop_names) {
|
|
1406
1458
|
if self.emit_default_scalar_proxy(out, f, name, ir, indent)
|
|
1459
|
+
|| self.emit_optional_enum_attribute_proxy(out, f, name, ir, indent)
|
|
1407
1460
|
|| self.emit_integer_proxy(out, f, name, ir, indent)
|
|
1408
1461
|
|| self.emit_temporal_proxy(out, f, name, ir, indent)
|
|
1409
1462
|
{
|
|
@@ -1471,6 +1524,7 @@ impl CSharpCodegen {
|
|
|
1471
1524
|
writeln!(out, "{} public {}() {{ }}", indent, struct_name).unwrap();
|
|
1472
1525
|
for (f, name) in s.fields.iter().zip(&prop_names) {
|
|
1473
1526
|
if self.emit_default_scalar_proxy(out, f, name, ir, indent)
|
|
1527
|
+
|| self.emit_optional_enum_attribute_proxy(out, f, name, ir, indent)
|
|
1474
1528
|
|| self.emit_integer_proxy(out, f, name, ir, indent)
|
|
1475
1529
|
|| self.emit_temporal_proxy(out, f, name, ir, indent)
|
|
1476
1530
|
{
|
|
@@ -1627,6 +1681,51 @@ impl CSharpCodegen {
|
|
|
1627
1681
|
writeln!(out, "{}}}\n", indent).unwrap();
|
|
1628
1682
|
}
|
|
1629
1683
|
|
|
1684
|
+
fn inherited_property_names(
|
|
1685
|
+
&self,
|
|
1686
|
+
s: &StructDef,
|
|
1687
|
+
ir: &SchemaIR,
|
|
1688
|
+
visited: &mut HashSet<QName>,
|
|
1689
|
+
) -> HashSet<String> {
|
|
1690
|
+
let Some(base) = s.base_type.as_ref() else {
|
|
1691
|
+
return HashSet::new();
|
|
1692
|
+
};
|
|
1693
|
+
if !visited.insert(base.clone()) {
|
|
1694
|
+
return HashSet::new();
|
|
1695
|
+
}
|
|
1696
|
+
let Some(TypeDef::Struct(parent)) = ir.types.get(base) else {
|
|
1697
|
+
return HashSet::new();
|
|
1698
|
+
};
|
|
1699
|
+
let mut names = self.inherited_property_names(parent, ir, visited);
|
|
1700
|
+
let mut ancestor_fields = Vec::new();
|
|
1701
|
+
let mut next = parent.base_type.as_ref();
|
|
1702
|
+
let mut seen = HashSet::new();
|
|
1703
|
+
while let Some(qname) = next {
|
|
1704
|
+
if !seen.insert(qname.clone()) {
|
|
1705
|
+
break;
|
|
1706
|
+
}
|
|
1707
|
+
let Some(TypeDef::Struct(ancestor)) = ir.types.get(qname) else {
|
|
1708
|
+
break;
|
|
1709
|
+
};
|
|
1710
|
+
ancestor_fields.extend(ancestor.fields.iter());
|
|
1711
|
+
next = ancestor.base_type.as_ref();
|
|
1712
|
+
}
|
|
1713
|
+
let enclosing = type_ident(&parent.qname);
|
|
1714
|
+
for field in &parent.fields {
|
|
1715
|
+
let inherited = ancestor_fields.iter().any(|f| {
|
|
1716
|
+
(field.kind == FieldKind::Text && f.kind == FieldKind::Text)
|
|
1717
|
+
|| (field.kind == f.kind
|
|
1718
|
+
&& field.xml_name == f.xml_name
|
|
1719
|
+
&& field.namespace == f.namespace
|
|
1720
|
+
&& field.name == f.name)
|
|
1721
|
+
});
|
|
1722
|
+
if !inherited {
|
|
1723
|
+
self.unique_property_name(&field.name, &mut names, Some(&enclosing));
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
names
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1630
1729
|
fn unique_property_name(
|
|
1631
1730
|
&self,
|
|
1632
1731
|
name: &str,
|
|
@@ -1333,7 +1333,10 @@ impl RustCodegen {
|
|
|
1333
1333
|
if field.kind != FieldKind::Element {
|
|
1334
1334
|
continue;
|
|
1335
1335
|
}
|
|
1336
|
-
let tags: Vec<String> = match self
|
|
1336
|
+
let tags: Vec<String> = match self
|
|
1337
|
+
.resolve_union_def(&field.type_ref, ir)
|
|
1338
|
+
.filter(|_| field.xml_name.is_empty())
|
|
1339
|
+
{
|
|
1337
1340
|
Some(u) => u
|
|
1338
1341
|
.branches
|
|
1339
1342
|
.iter()
|
|
@@ -1495,7 +1498,10 @@ impl RustCodegen {
|
|
|
1495
1498
|
}
|
|
1496
1499
|
|
|
1497
1500
|
for meta in &elem_fields {
|
|
1498
|
-
if let Some(union_def) = self
|
|
1501
|
+
if let Some(union_def) = self
|
|
1502
|
+
.resolve_union_def(&meta.field.type_ref, ir)
|
|
1503
|
+
.filter(|_| meta.field.xml_name.is_empty())
|
|
1504
|
+
{
|
|
1499
1505
|
let branch_tags: Vec<_> = union_def
|
|
1500
1506
|
.branches
|
|
1501
1507
|
.iter()
|
|
@@ -1575,7 +1581,10 @@ impl RustCodegen {
|
|
|
1575
1581
|
);
|
|
1576
1582
|
}
|
|
1577
1583
|
for meta in &elem_fields {
|
|
1578
|
-
if let Some(union_def) = self
|
|
1584
|
+
if let Some(union_def) = self
|
|
1585
|
+
.resolve_union_def(&meta.field.type_ref, ir)
|
|
1586
|
+
.filter(|_| meta.field.xml_name.is_empty())
|
|
1587
|
+
{
|
|
1579
1588
|
let branch_tags: Vec<_> = union_def
|
|
1580
1589
|
.branches
|
|
1581
1590
|
.iter()
|
|
@@ -2069,10 +2078,14 @@ impl RustCodegen {
|
|
|
2069
2078
|
} else {
|
|
2070
2079
|
let target_type = self.format_rust_type_ref(&field.type_ref, types_with_lifetime);
|
|
2071
2080
|
let target_clean = target_type.split('<').next().unwrap_or(&target_type);
|
|
2081
|
+
let decode = if self.resolve_union_def(&field.type_ref, ir).is_some() {
|
|
2082
|
+
"decode_xml_wrapped"
|
|
2083
|
+
} else {
|
|
2084
|
+
"decode_xml"
|
|
2085
|
+
};
|
|
2072
2086
|
let _ = writeln!(
|
|
2073
2087
|
out,
|
|
2074
|
-
" let val = {}::
|
|
2075
|
-
target_clean
|
|
2088
|
+
" let val = {target_clean}::{decode}(reader, &e)?;"
|
|
2076
2089
|
);
|
|
2077
2090
|
let final_val = if is_boxed { "Box::new(val)" } else { "val" };
|
|
2078
2091
|
if is_list {
|
|
@@ -2102,6 +2115,10 @@ impl RustCodegen {
|
|
|
2102
2115
|
let is_list = field.cardinality.is_list() || field.type_ref.is_list();
|
|
2103
2116
|
let is_boxed = field.is_cycle_cut || field.type_ref.is_boxed();
|
|
2104
2117
|
|
|
2118
|
+
if self.resolve_union_def(&field.type_ref, ir).is_some() {
|
|
2119
|
+
let _ = writeln!(out, " return Err(PolyXmlError::SchemaError(\"Missing choice in {}\".into()));", field.xml_name);
|
|
2120
|
+
return;
|
|
2121
|
+
}
|
|
2105
2122
|
if self.field_is_string(&field.type_ref, ir) {
|
|
2106
2123
|
self.emit_pattern_check(out, field, "\"\"", ir);
|
|
2107
2124
|
if self.options.zero_copy {
|
|
@@ -2399,7 +2416,15 @@ impl RustCodegen {
|
|
|
2399
2416
|
field.xml_name
|
|
2400
2417
|
);
|
|
2401
2418
|
} else if self.resolve_union_def(&field.type_ref, ir).is_some() {
|
|
2402
|
-
|
|
2419
|
+
if field.xml_name.is_empty() {
|
|
2420
|
+
let _ = writeln!(out, " item.encode_xml(writer, None)?;");
|
|
2421
|
+
} else {
|
|
2422
|
+
let _ = writeln!(
|
|
2423
|
+
out,
|
|
2424
|
+
" item.encode_xml_wrapped(writer, {:?})?;",
|
|
2425
|
+
field.xml_name
|
|
2426
|
+
);
|
|
2427
|
+
}
|
|
2403
2428
|
} else {
|
|
2404
2429
|
let _ = writeln!(
|
|
2405
2430
|
out,
|
|
@@ -2451,7 +2476,15 @@ impl RustCodegen {
|
|
|
2451
2476
|
field.xml_name
|
|
2452
2477
|
);
|
|
2453
2478
|
} else if self.resolve_union_def(&field.type_ref, ir).is_some() {
|
|
2454
|
-
|
|
2479
|
+
if field.xml_name.is_empty() {
|
|
2480
|
+
let _ = writeln!(out, " val.encode_xml(writer, None)?;");
|
|
2481
|
+
} else {
|
|
2482
|
+
let _ = writeln!(
|
|
2483
|
+
out,
|
|
2484
|
+
" val.encode_xml_wrapped(writer, {:?})?;",
|
|
2485
|
+
field.xml_name
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2455
2488
|
} else {
|
|
2456
2489
|
let _ = writeln!(
|
|
2457
2490
|
out,
|
|
@@ -2506,7 +2539,15 @@ impl RustCodegen {
|
|
|
2506
2539
|
field.xml_name
|
|
2507
2540
|
);
|
|
2508
2541
|
} else if self.resolve_union_def(&field.type_ref, ir).is_some() {
|
|
2509
|
-
|
|
2542
|
+
if field.xml_name.is_empty() {
|
|
2543
|
+
let _ = writeln!(out, " self.{}.encode_xml(writer, None)?;", rust_name);
|
|
2544
|
+
} else {
|
|
2545
|
+
let _ = writeln!(
|
|
2546
|
+
out,
|
|
2547
|
+
" self.{}.encode_xml_wrapped(writer, {:?})?;",
|
|
2548
|
+
rust_name, field.xml_name
|
|
2549
|
+
);
|
|
2550
|
+
}
|
|
2510
2551
|
} else {
|
|
2511
2552
|
let _ = writeln!(
|
|
2512
2553
|
out,
|
|
@@ -2540,6 +2581,35 @@ impl RustCodegen {
|
|
|
2540
2581
|
out.push('\n');
|
|
2541
2582
|
let _ = writeln!(out, "{} {{", impl_header);
|
|
2542
2583
|
|
|
2584
|
+
let reader_lifetime = if needs_lifetime { "'a" } else { "'_" };
|
|
2585
|
+
let _ = writeln!(out, " pub fn decode_xml_wrapped(reader: &mut Reader<&{reader_lifetime} [u8]>, start: &BytesStart<'_>) -> Result<Self> {{");
|
|
2586
|
+
out.push_str(r#" let mut value = None;
|
|
2587
|
+
loop {
|
|
2588
|
+
match reader.read_event()? {
|
|
2589
|
+
Event::Start(e) => {
|
|
2590
|
+
if value.is_some() { return Err(PolyXmlError::SchemaError("Multiple choice alternatives".into())); }
|
|
2591
|
+
value = Some(Self::decode_xml(reader, &e)?);
|
|
2592
|
+
}
|
|
2593
|
+
Event::Empty(e) => {
|
|
2594
|
+
if value.is_some() { return Err(PolyXmlError::SchemaError("Multiple choice alternatives".into())); }
|
|
2595
|
+
let mut empty_reader = Reader::from_str("");
|
|
2596
|
+
value = Some(Self::decode_xml(&mut empty_reader, &e)?);
|
|
2597
|
+
}
|
|
2598
|
+
Event::End(e) if e.name() == start.name() => break,
|
|
2599
|
+
Event::Eof => return Err(PolyXmlError::SchemaError("Unclosed choice wrapper".into())),
|
|
2600
|
+
_ => {}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
value.ok_or_else(|| PolyXmlError::SchemaError("Missing choice alternative".into()))
|
|
2604
|
+
}
|
|
2605
|
+
pub fn encode_xml_wrapped<W: std::io::Write>(&self, writer: &mut Writer<W>, tag: &str) -> Result<()> {
|
|
2606
|
+
writer.write_event(Event::Start(BytesStart::new(tag)))?;
|
|
2607
|
+
self.encode_xml(writer, None)?;
|
|
2608
|
+
writer.write_event(Event::End(BytesEnd::new(tag)))?;
|
|
2609
|
+
Ok(())
|
|
2610
|
+
}
|
|
2611
|
+
"#);
|
|
2612
|
+
|
|
2543
2613
|
let from_xml_sig = if needs_lifetime {
|
|
2544
2614
|
"pub fn from_xml(xml: &'a str) -> Result<Self>"
|
|
2545
2615
|
} else {
|
|
@@ -350,20 +350,13 @@ impl XsdParser {
|
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
"attribute" => {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
&ty,
|
|
361
|
-
target_namespace.as_deref(),
|
|
362
|
-
&prefixes,
|
|
363
|
-
)
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
skip_subtree(&mut reader)?;
|
|
353
|
+
self.parse_global_attribute(
|
|
354
|
+
&mut reader,
|
|
355
|
+
e,
|
|
356
|
+
target_namespace.as_deref(),
|
|
357
|
+
&prefixes,
|
|
358
|
+
&mut ir,
|
|
359
|
+
)?;
|
|
367
360
|
}
|
|
368
361
|
"group" => {
|
|
369
362
|
// Named model group definition.
|
|
@@ -445,18 +438,19 @@ impl XsdParser {
|
|
|
445
438
|
}
|
|
446
439
|
}
|
|
447
440
|
"attribute" => {
|
|
448
|
-
if let
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
ir.attributes
|
|
452
|
-
.entry(QName::new(target_namespace.as_deref(), name))
|
|
453
|
-
.or_insert_with(|| {
|
|
441
|
+
if let Some(name) = get_attr_value(e, "name") {
|
|
442
|
+
let type_ref = get_attr_value(e, "type")
|
|
443
|
+
.map(|ty| {
|
|
454
444
|
resolve_type_ref(
|
|
455
445
|
&ty,
|
|
456
446
|
target_namespace.as_deref(),
|
|
457
447
|
&prefixes,
|
|
458
448
|
)
|
|
459
|
-
})
|
|
449
|
+
})
|
|
450
|
+
.unwrap_or_else(TypeRef::string);
|
|
451
|
+
ir.attributes
|
|
452
|
+
.entry(QName::new(target_namespace.as_deref(), name))
|
|
453
|
+
.or_insert(type_ref);
|
|
460
454
|
}
|
|
461
455
|
}
|
|
462
456
|
"group" => {
|
|
@@ -1225,6 +1219,7 @@ impl XsdParser {
|
|
|
1225
1219
|
let mut facets = RestrictionFacets::default();
|
|
1226
1220
|
let mut enum_values = Vec::new();
|
|
1227
1221
|
let mut union_branches: Option<Vec<UnionBranch>> = None;
|
|
1222
|
+
let mut list_requires_inline = false;
|
|
1228
1223
|
let mut documentation = None;
|
|
1229
1224
|
let mut buf = Vec::new();
|
|
1230
1225
|
|
|
@@ -1252,14 +1247,30 @@ impl XsdParser {
|
|
|
1252
1247
|
&item, target_ns, prefixes,
|
|
1253
1248
|
)));
|
|
1254
1249
|
} else {
|
|
1255
|
-
|
|
1256
|
-
"xs:list requires a supported itemType".into(),
|
|
1257
|
-
));
|
|
1250
|
+
list_requires_inline = true;
|
|
1258
1251
|
}
|
|
1259
1252
|
}
|
|
1260
1253
|
"union" => {
|
|
1261
1254
|
union_branches = Some(parse_union_members(e, target_ns, prefixes));
|
|
1262
1255
|
}
|
|
1256
|
+
"simpleType" if list_requires_inline => {
|
|
1257
|
+
let item_name =
|
|
1258
|
+
unique_type_name(ir, target_ns, &format!("{}Item", qname.local));
|
|
1259
|
+
if let Some(item) = self.parse_simple_type(
|
|
1260
|
+
reader,
|
|
1261
|
+
e,
|
|
1262
|
+
target_ns,
|
|
1263
|
+
prefixes,
|
|
1264
|
+
Some(item_name),
|
|
1265
|
+
ir,
|
|
1266
|
+
)? {
|
|
1267
|
+
base_type =
|
|
1268
|
+
TypeRef::List(Box::new(TypeRef::Named(item.qname().clone())));
|
|
1269
|
+
ir.add_type(item);
|
|
1270
|
+
list_requires_inline = false;
|
|
1271
|
+
}
|
|
1272
|
+
depth -= 1;
|
|
1273
|
+
}
|
|
1263
1274
|
"simpleType" if union_branches.is_some() => {
|
|
1264
1275
|
let branch_index = union_branches.as_ref().unwrap().len() + 1;
|
|
1265
1276
|
let inline_name = unique_type_name(
|
|
@@ -1380,7 +1391,12 @@ impl XsdParser {
|
|
|
1380
1391
|
_ => {}
|
|
1381
1392
|
}
|
|
1382
1393
|
}
|
|
1383
|
-
Event::End(
|
|
1394
|
+
Event::End(ref e) => {
|
|
1395
|
+
if strip_prefix(e.name().into_inner()) == "list" && list_requires_inline {
|
|
1396
|
+
return Err(SchemaError::Malformed(
|
|
1397
|
+
"xs:list requires itemType or an inline simpleType".into(),
|
|
1398
|
+
));
|
|
1399
|
+
}
|
|
1384
1400
|
depth -= 1;
|
|
1385
1401
|
}
|
|
1386
1402
|
Event::Eof => break,
|
|
@@ -1465,6 +1481,46 @@ impl XsdParser {
|
|
|
1465
1481
|
}
|
|
1466
1482
|
}
|
|
1467
1483
|
|
|
1484
|
+
fn parse_global_attribute(
|
|
1485
|
+
&self,
|
|
1486
|
+
reader: &mut Reader<&[u8]>,
|
|
1487
|
+
start: &BytesStart,
|
|
1488
|
+
target_ns: Option<&str>,
|
|
1489
|
+
prefixes: &HashMap<String, String>,
|
|
1490
|
+
ir: &mut SchemaIR,
|
|
1491
|
+
) -> Result<(), SchemaError> {
|
|
1492
|
+
let Some(name) = get_attr_value(start, "name") else {
|
|
1493
|
+
return skip_subtree(reader);
|
|
1494
|
+
};
|
|
1495
|
+
let mut type_ref = get_attr_value(start, "type")
|
|
1496
|
+
.map(|ty| resolve_type_ref(&ty, target_ns, prefixes))
|
|
1497
|
+
.unwrap_or_else(TypeRef::string);
|
|
1498
|
+
loop {
|
|
1499
|
+
match reader.read_event()? {
|
|
1500
|
+
Event::Start(e) if strip_prefix(e.name().into_inner()) == "simpleType" => {
|
|
1501
|
+
let anonymous_name =
|
|
1502
|
+
unique_type_name(ir, target_ns, &format!("{name}AttributeType"));
|
|
1503
|
+
if let Some(definition) = self.parse_simple_type(
|
|
1504
|
+
reader,
|
|
1505
|
+
&e,
|
|
1506
|
+
target_ns,
|
|
1507
|
+
prefixes,
|
|
1508
|
+
Some(anonymous_name),
|
|
1509
|
+
ir,
|
|
1510
|
+
)? {
|
|
1511
|
+
type_ref = TypeRef::Named(definition.qname().clone());
|
|
1512
|
+
ir.add_type(definition);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
Event::Start(_) => skip_subtree(reader)?,
|
|
1516
|
+
Event::End(_) | Event::Eof => break,
|
|
1517
|
+
_ => {}
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
ir.attributes.insert(QName::new(target_ns, name), type_ref);
|
|
1521
|
+
Ok(())
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1468
1524
|
fn parse_global_element(
|
|
1469
1525
|
&mut self,
|
|
1470
1526
|
reader: &mut Reader<&[u8]>,
|
|
@@ -2728,6 +2784,7 @@ fn validate_type_references(ir: &SchemaIR, xml: &str) -> Result<(), SchemaError>
|
|
|
2728
2784
|
}
|
|
2729
2785
|
fn validate_schema_grammar(xml: &str) -> Result<(), SchemaError> {
|
|
2730
2786
|
let mut reader = Reader::from_str(xml);
|
|
2787
|
+
let mut schema_namespace = None;
|
|
2731
2788
|
let mut stack = Vec::<(String, HashMap<String, String>)>::new();
|
|
2732
2789
|
let mut line = 1;
|
|
2733
2790
|
let mut line_position = 0;
|
|
@@ -2754,6 +2811,9 @@ fn validate_schema_grammar(xml: &str) -> Result<(), SchemaError> {
|
|
|
2754
2811
|
}
|
|
2755
2812
|
}
|
|
2756
2813
|
let local = strip_prefix(element.name().into_inner());
|
|
2814
|
+
if stack.is_empty() && local == "schema" {
|
|
2815
|
+
schema_namespace = get_attr_value(&element, "targetNamespace");
|
|
2816
|
+
}
|
|
2757
2817
|
let position = reader.buffer_position() as usize;
|
|
2758
2818
|
line += xml[line_position..position]
|
|
2759
2819
|
.bytes()
|
|
@@ -2804,6 +2864,9 @@ fn validate_schema_grammar(xml: &str) -> Result<(), SchemaError> {
|
|
|
2804
2864
|
)));
|
|
2805
2865
|
};
|
|
2806
2866
|
if namespace == "http://www.w3.org/2001/XMLSchema"
|
|
2867
|
+
// The schema-for-schemas declares named types in this
|
|
2868
|
+
// namespace; the resolved IR validates their existence.
|
|
2869
|
+
&& schema_namespace.as_deref() != Some(namespace.as_str())
|
|
2807
2870
|
&& attr.key.as_ref() != "ref"
|
|
2808
2871
|
&& PrimitiveType::from_xsd_name(local).is_none()
|
|
2809
2872
|
{
|