polyxml 0.34.2__tar.gz → 0.34.3__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.3}/Cargo.lock +6 -6
- {polyxml-0.34.2 → polyxml-0.34.3}/Cargo.toml +1 -1
- {polyxml-0.34.2 → polyxml-0.34.3}/PKG-INFO +1 -1
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/csharp/mod.rs +51 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/schema_parser/mod.rs +88 -25
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_qualified_attributes.rs +50 -3
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_schema_ir.rs +137 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/pyproject.toml +1 -1
- {polyxml-0.34.2 → polyxml-0.34.3}/README.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/integer.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/ir/chunker.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/ir/particle.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/parser.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/schema.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/schema_parser/upa.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/serializer.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_any_attribute.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_any_element.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_lexical_lists.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_temporal_union.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_ubl_csharp.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_upa.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_value_constraints.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/src/lib.rs +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/python/polyxml/__init__.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.34.2 → polyxml-0.34.3}/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.3"
|
|
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.3"
|
|
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.3"
|
|
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.3"
|
|
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.3"
|
|
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.3"
|
|
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,
|
|
@@ -1392,6 +1439,8 @@ impl CSharpCodegen {
|
|
|
1392
1439
|
}
|
|
1393
1440
|
|
|
1394
1441
|
let has_lexical_union = self.options.emit_xml_attributes && s.fields.iter().any(|f| {
|
|
1442
|
+
(f.kind == FieldKind::Attribute && f.cardinality.is_optional()
|
|
1443
|
+
&& matches!(&f.type_ref, TypeRef::Named(q) if matches!(ir.types.get(q), Some(TypeDef::Enum(_))))) ||
|
|
1395
1444
|
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
1445
|
});
|
|
1397
1446
|
|
|
@@ -1404,6 +1453,7 @@ impl CSharpCodegen {
|
|
|
1404
1453
|
.unwrap();
|
|
1405
1454
|
for (f, name) in s.fields.iter().zip(&prop_names) {
|
|
1406
1455
|
if self.emit_default_scalar_proxy(out, f, name, ir, indent)
|
|
1456
|
+
|| self.emit_optional_enum_attribute_proxy(out, f, name, ir, indent)
|
|
1407
1457
|
|| self.emit_integer_proxy(out, f, name, ir, indent)
|
|
1408
1458
|
|| self.emit_temporal_proxy(out, f, name, ir, indent)
|
|
1409
1459
|
{
|
|
@@ -1471,6 +1521,7 @@ impl CSharpCodegen {
|
|
|
1471
1521
|
writeln!(out, "{} public {}() {{ }}", indent, struct_name).unwrap();
|
|
1472
1522
|
for (f, name) in s.fields.iter().zip(&prop_names) {
|
|
1473
1523
|
if self.emit_default_scalar_proxy(out, f, name, ir, indent)
|
|
1524
|
+
|| self.emit_optional_enum_attribute_proxy(out, f, name, ir, indent)
|
|
1474
1525
|
|| self.emit_integer_proxy(out, f, name, ir, indent)
|
|
1475
1526
|
|| self.emit_temporal_proxy(out, f, name, ir, indent)
|
|
1476
1527
|
{
|
|
@@ -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
|
{
|
|
@@ -15,11 +15,35 @@ fn global_attribute_references_round_trip_by_namespace() {
|
|
|
15
15
|
"/../../research/fixtures/wave6/xlink_shared_attribute/root.xsd"
|
|
16
16
|
))
|
|
17
17
|
.unwrap();
|
|
18
|
+
assert_attribute_round_trip(&ir);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#[test]
|
|
22
|
+
fn imported_inline_global_attribute_enum_round_trips() {
|
|
23
|
+
let fixture = tempdir().unwrap();
|
|
24
|
+
fs::copy(
|
|
25
|
+
concat!(
|
|
26
|
+
env!("CARGO_MANIFEST_DIR"),
|
|
27
|
+
"/../../research/fixtures/wave6/xlink_shared_attribute/root.xsd"
|
|
28
|
+
),
|
|
29
|
+
fixture.path().join("root.xsd"),
|
|
30
|
+
)
|
|
31
|
+
.unwrap();
|
|
32
|
+
fs::write(fixture.path().join("xlink.xsd"), r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/1999/xlink">
|
|
33
|
+
<xs:attribute name="type"><xs:simpleType><xs:restriction base="xs:string"><xs:enumeration value="resource"/><xs:enumeration value="arc"/></xs:restriction></xs:simpleType></xs:attribute>
|
|
34
|
+
</xs:schema>"#).unwrap();
|
|
35
|
+
let ir = XsdParser::new()
|
|
36
|
+
.parse_file(fixture.path().join("root.xsd"))
|
|
37
|
+
.unwrap();
|
|
38
|
+
assert_attribute_round_trip(&ir);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fn assert_attribute_round_trip(ir: &polyxml::ir::SchemaIR) {
|
|
18
42
|
let temp = tempdir().unwrap();
|
|
19
43
|
fs::write(temp.path().join("go.mod"), "module attrs\n\ngo 1.22\n").unwrap();
|
|
20
44
|
fs::write(
|
|
21
45
|
temp.path().join("models.go"),
|
|
22
|
-
GoCodegen::new(GoOptions::default()).generate_module(
|
|
46
|
+
GoCodegen::new(GoOptions::default()).generate_module(ir),
|
|
23
47
|
)
|
|
24
48
|
.unwrap();
|
|
25
49
|
fs::write(temp.path().join("models_test.go"), r#"package models
|
|
@@ -32,6 +56,8 @@ func TestAttributes(t *testing.T) {
|
|
|
32
56
|
for {token,err:=decoder.Token();if err==io.EOF{break};if err!=nil{t.Fatal(err)};if start,ok:=token.(xml.StartElement);ok{for _,attr:=range start.Attr{if attr.Name.Space=="http://www.w3.org/1999/xlink"&&attr.Name.Local=="type"{count++;if attr.Value!="resource"&&attr.Value!="arc"{t.Fatal(attr)}}}}}
|
|
33
57
|
if count!=2{t.Fatalf("attributes lost: %s",data)}
|
|
34
58
|
}
|
|
59
|
+
var absent Links; if err:=xml.Unmarshal([]byte(`<Links><Resource/><Arc/></Links>`),&absent);err!=nil{t.Fatal(err)}
|
|
60
|
+
data,err:=xml.Marshal(absent);if err!=nil{t.Fatal(err)};if strings.Contains(string(data),`type=`){t.Fatalf("absent attribute emitted: %s",data)}
|
|
35
61
|
}"#).unwrap();
|
|
36
62
|
let result = Command::new("go")
|
|
37
63
|
.args(["test", "./..."])
|
|
@@ -54,7 +80,7 @@ func TestAttributes(t *testing.T) {
|
|
|
54
80
|
use_records,
|
|
55
81
|
..Default::default()
|
|
56
82
|
})
|
|
57
|
-
.generate_module(
|
|
83
|
+
.generate_module(ir),
|
|
58
84
|
)
|
|
59
85
|
.unwrap();
|
|
60
86
|
fs::write(temp.path().join("Program.cs"), r#"using System.Xml.Serialization;using System.Xml.Linq;using Models;
|
|
@@ -62,9 +88,30 @@ var serializer=new XmlSerializer(typeof(Links));
|
|
|
62
88
|
foreach(var document in new[]{"<Links xmlns:xl='http://www.w3.org/1999/xlink'><Resource xl:type='resource'/><Arc xl:type='arc'/></Links>","<Links><Resource xmlns:b='http://www.w3.org/1999/xlink' b:type='resource'/><Arc xmlns:c='http://www.w3.org/1999/xlink' c:type='arc'/></Links>"}){
|
|
63
89
|
var root=(Links)serializer.Deserialize(new StringReader(document))!;
|
|
64
90
|
var writer=new StringWriter();serializer.Serialize(writer,root);
|
|
91
|
+
using(var jsonDocument=System.Text.Json.JsonSerializer.SerializeToDocument(root)){
|
|
92
|
+
if(!jsonDocument.RootElement.GetProperty("Resource").TryGetProperty("type",out _))throw new Exception("JSON wire name lost");
|
|
93
|
+
}
|
|
65
94
|
var xml=XDocument.Parse(writer.ToString());XNamespace ns="http://www.w3.org/1999/xlink";
|
|
66
95
|
if((string?)xml.Root!.Element("Resource")!.Attribute(ns+"type")!="resource"||(string?)xml.Root.Element("Arc")!.Attribute(ns+"type")!="arc")throw new Exception(writer.ToString());
|
|
67
|
-
}
|
|
96
|
+
}
|
|
97
|
+
var absent=(Links)serializer.Deserialize(new StringReader("<Links><Resource/><Arc/></Links>"))!;
|
|
98
|
+
var absentWriter=new StringWriter();serializer.Serialize(absentWriter,absent);
|
|
99
|
+
if(XDocument.Parse(absentWriter.ToString()).Descendants().Attributes().Any(a=>a.Name.LocalName=="type"))throw new Exception(absentWriter.ToString());
|
|
100
|
+
var json=System.Text.Json.JsonSerializer.Serialize(absent);
|
|
101
|
+
if(json.Contains("TypeXml"))throw new Exception("XML proxy leaked to JSON: "+json);
|
|
102
|
+
"#).unwrap();
|
|
103
|
+
if ir
|
|
104
|
+
.types
|
|
105
|
+
.values()
|
|
106
|
+
.any(|definition| matches!(definition, polyxml::ir::TypeDef::Enum(_)))
|
|
107
|
+
{
|
|
108
|
+
use std::io::Write;
|
|
109
|
+
let mut program = fs::OpenOptions::new()
|
|
110
|
+
.append(true)
|
|
111
|
+
.open(temp.path().join("Program.cs"))
|
|
112
|
+
.unwrap();
|
|
113
|
+
writeln!(program, r#"bool rejected=false;try{{serializer.Deserialize(new StringReader("<Links xmlns:x='http://www.w3.org/1999/xlink'><Resource x:type='invalid'/><Arc/></Links>"));}}catch(InvalidOperationException){{rejected=true;}}if(!rejected)throw new Exception("invalid enum accepted");"#).unwrap();
|
|
114
|
+
}
|
|
68
115
|
let result = Command::new("dotnet")
|
|
69
116
|
.arg("run")
|
|
70
117
|
.current_dir(temp.path())
|
|
@@ -652,3 +652,140 @@ fn schema_errors_preserve_forward_imports_and_annotation_payloads() {
|
|
|
652
652
|
assert!(XsdParser::new().parse_str(schema).is_err());
|
|
653
653
|
}
|
|
654
654
|
}
|
|
655
|
+
|
|
656
|
+
#[test]
|
|
657
|
+
fn imported_inline_global_attribute_types_are_resolved() {
|
|
658
|
+
let dir = tempdir().unwrap();
|
|
659
|
+
std::fs::write(dir.path().join("attributes.xsd"), r#"<s:schema xmlns:s="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:attrs">
|
|
660
|
+
<s:attribute name="code"><s:annotation><s:documentation>Inline enum</s:documentation></s:annotation><s:simpleType><s:restriction base="s:string"><s:enumeration value="arc"/><s:enumeration value="resource"/></s:restriction></s:simpleType></s:attribute>
|
|
661
|
+
<s:attribute name="number"><s:simpleType><s:restriction base="s:int"><s:minInclusive value="3"/></s:restriction></s:simpleType></s:attribute>
|
|
662
|
+
<s:attribute name="lang"><s:simpleType><s:union memberTypes="s:language"><s:simpleType><s:restriction base="s:string"><s:enumeration value=""/></s:restriction></s:simpleType></s:union></s:simpleType></s:attribute>
|
|
663
|
+
<s:attribute name="plain"/>
|
|
664
|
+
<s:attribute name="annotated"><s:annotation><s:documentation>Untyped</s:documentation></s:annotation></s:attribute>
|
|
665
|
+
</s:schema>"#).unwrap();
|
|
666
|
+
let root = dir.path().join("root.xsd");
|
|
667
|
+
std::fs::write(&root, r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:a="urn:attrs">
|
|
668
|
+
<xs:import namespace="urn:attrs" schemaLocation="attributes.xsd"/>
|
|
669
|
+
<xs:complexType name="Record"><xs:attribute ref="a:code" use="required"/><xs:attribute ref="a:number"/><xs:attribute ref="a:lang"/><xs:attribute ref="a:plain"/><xs:attribute ref="a:annotated"/></xs:complexType>
|
|
670
|
+
</xs:schema>"#).unwrap();
|
|
671
|
+
let ir = XsdParser::new().parse_file(&root).unwrap();
|
|
672
|
+
let TypeDef::Struct(record) = &ir.types[&QName::new(None::<String>, "Record")] else {
|
|
673
|
+
panic!("Record");
|
|
674
|
+
};
|
|
675
|
+
for field in &record.fields {
|
|
676
|
+
assert_eq!(field.namespace.as_deref(), Some("urn:attrs"));
|
|
677
|
+
assert_eq!(
|
|
678
|
+
field.type_ref,
|
|
679
|
+
ir.attributes[&QName::new(Some("urn:attrs"), &field.xml_name)]
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
assert_eq!(record.fields[0].cardinality, Cardinality::required_one());
|
|
683
|
+
let TypeRef::Named(enum_name) = &record.fields[0].type_ref else {
|
|
684
|
+
panic!("enum type");
|
|
685
|
+
};
|
|
686
|
+
let TypeDef::Enum(enumeration) = &ir.types[enum_name] else {
|
|
687
|
+
panic!("enum declaration");
|
|
688
|
+
};
|
|
689
|
+
assert_eq!(
|
|
690
|
+
enumeration
|
|
691
|
+
.variants
|
|
692
|
+
.iter()
|
|
693
|
+
.map(|v| v.value.as_str())
|
|
694
|
+
.collect::<Vec<_>>(),
|
|
695
|
+
["arc", "resource"]
|
|
696
|
+
);
|
|
697
|
+
let TypeRef::Named(number_name) = &record.fields[1].type_ref else {
|
|
698
|
+
panic!("number type");
|
|
699
|
+
};
|
|
700
|
+
let TypeDef::Simple(number) = &ir.types[number_name] else {
|
|
701
|
+
panic!("restriction");
|
|
702
|
+
};
|
|
703
|
+
assert_eq!(number.base_type, TypeRef::Primitive(PrimitiveType::Int));
|
|
704
|
+
assert_eq!(number.facets.min_inclusive.as_deref(), Some("3"));
|
|
705
|
+
let TypeRef::Named(union_name) = &record.fields[2].type_ref else {
|
|
706
|
+
panic!("union type");
|
|
707
|
+
};
|
|
708
|
+
let TypeDef::Union(union) = &ir.types[union_name] else {
|
|
709
|
+
panic!("union declaration");
|
|
710
|
+
};
|
|
711
|
+
assert!(union.is_lexical());
|
|
712
|
+
assert_eq!(union.branches.len(), 2);
|
|
713
|
+
assert_eq!(record.fields[3].type_ref, TypeRef::string());
|
|
714
|
+
assert_eq!(record.fields[4].type_ref, TypeRef::string());
|
|
715
|
+
let invalid = std::fs::read_to_string(&root)
|
|
716
|
+
.unwrap()
|
|
717
|
+
.replace("a:code", "a:missing");
|
|
718
|
+
std::fs::write(&root, invalid).unwrap();
|
|
719
|
+
assert!(XsdParser::new()
|
|
720
|
+
.parse_file(&root)
|
|
721
|
+
.unwrap_err()
|
|
722
|
+
.to_string()
|
|
723
|
+
.contains("Unresolved type"));
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
#[test]
|
|
727
|
+
fn schema_for_schemas_declared_types_are_not_unknown_builtins() {
|
|
728
|
+
let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/2001/XMLSchema">
|
|
729
|
+
<xs:complexType name="Derived"><xs:complexContent><xs:extension base="xs:openAttrs"><xs:attribute name="name" type="xs:string"/></xs:extension></xs:complexContent></xs:complexType>
|
|
730
|
+
<xs:complexType name="openAttrs"><xs:anyAttribute processContents="lax"/></xs:complexType>
|
|
731
|
+
<xs:element name="Root" type="xs:Derived"/>
|
|
732
|
+
</xs:schema>"#;
|
|
733
|
+
let ir = XsdParser::new().parse_str(xsd).unwrap();
|
|
734
|
+
let ns = Some("http://www.w3.org/2001/XMLSchema");
|
|
735
|
+
let TypeDef::Struct(derived) = &ir.types[&QName::new(ns, "Derived")] else {
|
|
736
|
+
panic!("Derived");
|
|
737
|
+
};
|
|
738
|
+
assert_eq!(derived.base_type, Some(QName::new(ns, "openAttrs")));
|
|
739
|
+
let missing = xsd.replace("base=\"xs:openAttrs\"", "base=\"xs:Misspelled\"");
|
|
740
|
+
assert!(XsdParser::new()
|
|
741
|
+
.parse_str(&missing)
|
|
742
|
+
.unwrap_err()
|
|
743
|
+
.to_string()
|
|
744
|
+
.contains("Misspelled"));
|
|
745
|
+
let normal = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:element name="Root" type="xs:NotAType"/></xs:schema>"#;
|
|
746
|
+
assert!(XsdParser::new()
|
|
747
|
+
.parse_str(normal)
|
|
748
|
+
.unwrap_err()
|
|
749
|
+
.to_string()
|
|
750
|
+
.contains("Unknown built-in type"));
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
#[test]
|
|
754
|
+
fn inline_list_item_types_preserve_enum_and_union_declarations() {
|
|
755
|
+
for item in [
|
|
756
|
+
r#"<xs:restriction base="xs:string"><xs:enumeration value="one"/><xs:enumeration value="two"/></xs:restriction>"#,
|
|
757
|
+
r#"<xs:union memberTypes="xs:int xs:string"/>"#,
|
|
758
|
+
] {
|
|
759
|
+
let xsd = format!(
|
|
760
|
+
r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:simpleType name="Values"><xs:list><xs:annotation><xs:documentation>items</xs:documentation></xs:annotation><xs:simpleType>{item}</xs:simpleType></xs:list></xs:simpleType></xs:schema>"#
|
|
761
|
+
);
|
|
762
|
+
let ir = XsdParser::new().parse_str(&xsd).unwrap();
|
|
763
|
+
let TypeDef::Simple(values) = &ir.types[&QName::new(None::<String>, "Values")] else {
|
|
764
|
+
panic!("list");
|
|
765
|
+
};
|
|
766
|
+
let TypeRef::List(inner) = &values.base_type else {
|
|
767
|
+
panic!("list reference");
|
|
768
|
+
};
|
|
769
|
+
let TypeRef::Named(name) = inner.as_ref() else {
|
|
770
|
+
panic!("item declaration");
|
|
771
|
+
};
|
|
772
|
+
match &ir.types[name] {
|
|
773
|
+
TypeDef::Enum(e) => assert_eq!(e.variants.len(), 2),
|
|
774
|
+
TypeDef::Union(u) => {
|
|
775
|
+
assert!(u.is_lexical());
|
|
776
|
+
assert_eq!(u.branches.len(), 2);
|
|
777
|
+
}
|
|
778
|
+
other => panic!("unexpected item: {other:?}"),
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
for list in ["<xs:list/>", "<xs:list></xs:list>"] {
|
|
782
|
+
let invalid = format!(
|
|
783
|
+
r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:simpleType name="Values">{list}</xs:simpleType></xs:schema>"#
|
|
784
|
+
);
|
|
785
|
+
assert!(XsdParser::new()
|
|
786
|
+
.parse_str(&invalid)
|
|
787
|
+
.unwrap_err()
|
|
788
|
+
.to_string()
|
|
789
|
+
.contains("xs:list requires"));
|
|
790
|
+
}
|
|
791
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polyxml-0.34.2 → polyxml-0.34.3}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs
RENAMED
|
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
|
|
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
|