polyxml 0.33.1__tar.gz → 0.33.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.33.1 → polyxml-0.33.3}/Cargo.lock +6 -6
- {polyxml-0.33.1 → polyxml-0.33.3}/Cargo.toml +1 -1
- {polyxml-0.33.1 → polyxml-0.33.3}/PKG-INFO +1 -1
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/go/mod.rs +333 -10
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/parser.rs +205 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/schema.rs +8 -1
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/schema_parser/mod.rs +71 -7
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/serializer.rs +105 -0
- polyxml-0.33.3/crates/polyxml-core/tests/test_any_element.rs +154 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_go_codegen.rs +129 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_python_codegen.rs +31 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/src/lib.rs +142 -10
- {polyxml-0.33.1 → polyxml-0.33.3}/pyproject.toml +1 -1
- {polyxml-0.33.1 → polyxml-0.33.3}/python/polyxml/__init__.py +12 -1
- {polyxml-0.33.1 → polyxml-0.33.3}/README.md +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/ir/chunker.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_any_attribute.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.33.1 → polyxml-0.33.3}/python/polyxml/py.typed +0 -0
|
@@ -608,7 +608,7 @@ dependencies = [
|
|
|
608
608
|
|
|
609
609
|
[[package]]
|
|
610
610
|
name = "polyxml"
|
|
611
|
-
version = "0.33.
|
|
611
|
+
version = "0.33.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.33.
|
|
632
|
+
version = "0.33.3"
|
|
633
633
|
dependencies = [
|
|
634
634
|
"polyxml",
|
|
635
635
|
]
|
|
636
636
|
|
|
637
637
|
[[package]]
|
|
638
638
|
name = "polyxml-cli"
|
|
639
|
-
version = "0.33.
|
|
639
|
+
version = "0.33.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.33.
|
|
653
|
+
version = "0.33.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.33.
|
|
663
|
+
version = "0.33.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.33.
|
|
673
|
+
version = "0.33.3"
|
|
674
674
|
dependencies = [
|
|
675
675
|
"polyxml",
|
|
676
676
|
"quick-xml",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use std::collections::HashSet;
|
|
2
2
|
use std::fmt::Write as FmtWrite;
|
|
3
3
|
|
|
4
|
-
use heck::{AsPascalCase, AsSnakeCase};
|
|
4
|
+
use heck::{AsLowerCamelCase, AsPascalCase, AsSnakeCase};
|
|
5
5
|
use serde::{Deserialize, Serialize};
|
|
6
6
|
|
|
7
7
|
use crate::codegen::{
|
|
@@ -361,7 +361,7 @@ impl GoCodegen {
|
|
|
361
361
|
{
|
|
362
362
|
imports.push("\"bytes\"");
|
|
363
363
|
}
|
|
364
|
-
if has_fmt {
|
|
364
|
+
if has_fmt || body.contains("fmt.") {
|
|
365
365
|
imports.push("\"fmt\"");
|
|
366
366
|
}
|
|
367
367
|
if has_io {
|
|
@@ -374,13 +374,12 @@ impl GoCodegen {
|
|
|
374
374
|
.types
|
|
375
375
|
.values()
|
|
376
376
|
.any(|def| matches!(def, TypeDef::Union(u) if u.is_lexical()))
|
|
377
|
+
&& body.contains("strconv.")
|
|
377
378
|
{
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
imports.push("\"strings\"");
|
|
383
|
-
}
|
|
379
|
+
imports.push("\"strconv\"");
|
|
380
|
+
}
|
|
381
|
+
if body.contains("strings.") {
|
|
382
|
+
imports.push("\"strings\"");
|
|
384
383
|
}
|
|
385
384
|
if has_time {
|
|
386
385
|
imports.push("\"time\"");
|
|
@@ -447,6 +446,14 @@ impl GoCodegen {
|
|
|
447
446
|
self.emit_struct(out, s, ir);
|
|
448
447
|
}
|
|
449
448
|
}
|
|
449
|
+
|
|
450
|
+
let has_any_element = ir.emitted_types().any(|t| match t {
|
|
451
|
+
TypeDef::Struct(s) => s.fields.iter().any(|f| f.kind == FieldKind::Any),
|
|
452
|
+
_ => false,
|
|
453
|
+
});
|
|
454
|
+
if has_any_element {
|
|
455
|
+
out.push_str("// AnyElement represents an unmapped wildcard XML element (xs:any).\ntype AnyElement struct {\n XMLName xml.Name\n Attrs []xml.Attr `xml:\",any,attr\" json:\"attrs,omitempty\"`\n Content string `xml:\",innerxml\" json:\"content,omitempty\"`\n}\n\n");
|
|
456
|
+
}
|
|
450
457
|
}
|
|
451
458
|
|
|
452
459
|
fn emit_simple_type(&self, out: &mut String, simple: &SimpleTypeDef, ir: &SchemaIR) {
|
|
@@ -905,6 +912,11 @@ impl GoCodegen {
|
|
|
905
912
|
}
|
|
906
913
|
|
|
907
914
|
fn emit_struct(&self, out: &mut String, s: &StructDef, ir: &SchemaIR) {
|
|
915
|
+
if s.is_abstract {
|
|
916
|
+
self.emit_abstract_struct(out, s, ir);
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
|
|
908
920
|
let struct_name = type_ident(&s.qname);
|
|
909
921
|
if let Some(ref doc) = s.documentation {
|
|
910
922
|
for line in doc.lines() {
|
|
@@ -937,9 +949,13 @@ impl GoCodegen {
|
|
|
937
949
|
// Struct composition / inheritance if base struct exists
|
|
938
950
|
let mut simple_content_base: Option<String> = None;
|
|
939
951
|
if let Some(ref base_qname) = s.base_type {
|
|
940
|
-
if
|
|
952
|
+
if let Some(TypeDef::Struct(base_s)) = ir.types.get(base_qname) {
|
|
941
953
|
let base_name = type_ident(base_qname);
|
|
942
|
-
|
|
954
|
+
if base_s.is_abstract {
|
|
955
|
+
writeln!(out, " {}Base", base_name).unwrap();
|
|
956
|
+
} else {
|
|
957
|
+
writeln!(out, " {}", base_name).unwrap();
|
|
958
|
+
}
|
|
943
959
|
} else if let Some(prim) = PrimitiveType::from_xsd_name(&base_qname.local) {
|
|
944
960
|
simple_content_base = Some(self.context.map_primitive(prim).to_string());
|
|
945
961
|
} else if let Some(TypeDef::Simple(st)) = ir.types.get(base_qname) {
|
|
@@ -1104,6 +1120,15 @@ impl GoCodegen {
|
|
|
1104
1120
|
if f.kind == FieldKind::AnyAttribute {
|
|
1105
1121
|
return "[]xml.Attr".to_string();
|
|
1106
1122
|
}
|
|
1123
|
+
if f.kind == FieldKind::Any {
|
|
1124
|
+
if f.cardinality.is_list() {
|
|
1125
|
+
return "[]AnyElement".to_string();
|
|
1126
|
+
} else if f.is_cycle_cut || f.cardinality.is_optional() || f.nillable {
|
|
1127
|
+
return "*AnyElement".to_string();
|
|
1128
|
+
} else {
|
|
1129
|
+
return "AnyElement".to_string();
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1107
1132
|
let base_type = self.context.map_type_ref(&f.type_ref);
|
|
1108
1133
|
|
|
1109
1134
|
if f.cardinality.is_list() {
|
|
@@ -1156,6 +1181,15 @@ impl GoCodegen {
|
|
|
1156
1181
|
if self.options.backend == GoBackend::Sonic {
|
|
1157
1182
|
parts.push("sonic:\"-\"".to_string());
|
|
1158
1183
|
}
|
|
1184
|
+
} else if f.kind == FieldKind::Any {
|
|
1185
|
+
let is_opt = f.cardinality.is_optional() || f.nillable;
|
|
1186
|
+
let tag = if is_opt { "any,omitempty" } else { "any" };
|
|
1187
|
+
if self.options.emit_json_tags {
|
|
1188
|
+
parts.push(format!("json:\"{}\"", tag));
|
|
1189
|
+
}
|
|
1190
|
+
if self.options.backend == GoBackend::Sonic {
|
|
1191
|
+
parts.push(format!("sonic:\"{}\"", tag));
|
|
1192
|
+
}
|
|
1159
1193
|
} else {
|
|
1160
1194
|
let is_opt = f.cardinality.is_optional() || f.nillable;
|
|
1161
1195
|
let raw_json_name = if f.kind == FieldKind::Text {
|
|
@@ -1244,6 +1278,264 @@ impl GoCodegen {
|
|
|
1244
1278
|
writeln!(out, "}}\n").unwrap();
|
|
1245
1279
|
}
|
|
1246
1280
|
|
|
1281
|
+
fn emit_abstract_struct(&self, out: &mut String, s: &StructDef, ir: &SchemaIR) {
|
|
1282
|
+
let struct_name = type_ident(&s.qname);
|
|
1283
|
+
let base_struct_name = format!("{}Base", struct_name);
|
|
1284
|
+
|
|
1285
|
+
if let Some(ref doc) = s.documentation {
|
|
1286
|
+
for line in doc.lines() {
|
|
1287
|
+
writeln!(out, "// {}", line).unwrap();
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// 1. Base struct definition holding declared fields of the abstract type
|
|
1292
|
+
writeln!(out, "type {} struct {{", base_struct_name).unwrap();
|
|
1293
|
+
if let Some(ref base_qname) = s.base_type {
|
|
1294
|
+
if let Some(TypeDef::Struct(base_s)) = ir.types.get(base_qname) {
|
|
1295
|
+
let base_name = type_ident(base_qname);
|
|
1296
|
+
if base_s.is_abstract {
|
|
1297
|
+
writeln!(out, " {}Base", base_name).unwrap();
|
|
1298
|
+
} else {
|
|
1299
|
+
writeln!(out, " {}", base_name).unwrap();
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
let mut seen_fields = HashSet::new();
|
|
1305
|
+
let field_names: Vec<String> = s
|
|
1306
|
+
.fields
|
|
1307
|
+
.iter()
|
|
1308
|
+
.map(|f| self.unique_field_name(&f.name, &mut seen_fields))
|
|
1309
|
+
.collect();
|
|
1310
|
+
|
|
1311
|
+
let mut seen_json = HashSet::new();
|
|
1312
|
+
for (f, field_name) in s.fields.iter().zip(&field_names) {
|
|
1313
|
+
let field_type = self.resolve_field_type(f);
|
|
1314
|
+
let tag = self.build_field_struct_tags(f, &mut seen_json);
|
|
1315
|
+
writeln!(out, " {} {}{}", field_name, field_type, tag).unwrap();
|
|
1316
|
+
}
|
|
1317
|
+
writeln!(out, "}}\n").unwrap();
|
|
1318
|
+
|
|
1319
|
+
writeln!(
|
|
1320
|
+
out,
|
|
1321
|
+
"func (s {}) Validate() error {{\n return nil\n}}\n",
|
|
1322
|
+
base_struct_name
|
|
1323
|
+
)
|
|
1324
|
+
.unwrap();
|
|
1325
|
+
|
|
1326
|
+
// 2. Discover concrete derivations
|
|
1327
|
+
let derivations = concrete_derivations(s, ir);
|
|
1328
|
+
|
|
1329
|
+
// 3. Dispatch wrapper struct
|
|
1330
|
+
writeln!(out, "type {} struct {{", struct_name).unwrap();
|
|
1331
|
+
if self.options.emit_xml_tags {
|
|
1332
|
+
let mut xml_tags = Vec::new();
|
|
1333
|
+
if self.options.emit_json_tags {
|
|
1334
|
+
xml_tags.push("json:\"-\"");
|
|
1335
|
+
}
|
|
1336
|
+
if self.options.backend == GoBackend::Sonic {
|
|
1337
|
+
xml_tags.push("sonic:\"-\"");
|
|
1338
|
+
}
|
|
1339
|
+
if xml_tags.is_empty() {
|
|
1340
|
+
writeln!(out, " XMLName xml.Name").unwrap();
|
|
1341
|
+
} else {
|
|
1342
|
+
writeln!(out, " XMLName xml.Name `{}`", xml_tags.join(" ")).unwrap();
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
writeln!(out, " {}", base_struct_name).unwrap();
|
|
1346
|
+
|
|
1347
|
+
let mut seen_derives = HashSet::new();
|
|
1348
|
+
let derive_fields: Vec<(String, String, String)> = derivations
|
|
1349
|
+
.iter()
|
|
1350
|
+
.map(|d| {
|
|
1351
|
+
let type_name = type_ident(&d.qname);
|
|
1352
|
+
let field_name = self.unique_field_name(&type_name, &mut seen_derives);
|
|
1353
|
+
(d.qname.local.clone(), field_name, type_name)
|
|
1354
|
+
})
|
|
1355
|
+
.collect();
|
|
1356
|
+
|
|
1357
|
+
for (_local, field_name, type_name) in &derive_fields {
|
|
1358
|
+
let json_name = AsLowerCamelCase(field_name).to_string();
|
|
1359
|
+
writeln!(
|
|
1360
|
+
out,
|
|
1361
|
+
" {} *{} `xml:\"-\" json:\"{},omitempty\"`",
|
|
1362
|
+
field_name, type_name, json_name
|
|
1363
|
+
)
|
|
1364
|
+
.unwrap();
|
|
1365
|
+
}
|
|
1366
|
+
writeln!(out, "}}\n").unwrap();
|
|
1367
|
+
|
|
1368
|
+
// 4. Methods on dispatch wrapper
|
|
1369
|
+
writeln!(out, "func (s {}) Selected() string {{", struct_name).unwrap();
|
|
1370
|
+
for (local, field_name, _) in &derive_fields {
|
|
1371
|
+
writeln!(
|
|
1372
|
+
out,
|
|
1373
|
+
" if s.{} != nil {{ return {:?} }}",
|
|
1374
|
+
field_name, local
|
|
1375
|
+
)
|
|
1376
|
+
.unwrap();
|
|
1377
|
+
}
|
|
1378
|
+
writeln!(out, " return \"\"\n}}\n").unwrap();
|
|
1379
|
+
|
|
1380
|
+
writeln!(out, "func (s {}) Value() any {{", struct_name).unwrap();
|
|
1381
|
+
for (_, field_name, _) in &derive_fields {
|
|
1382
|
+
writeln!(
|
|
1383
|
+
out,
|
|
1384
|
+
" if s.{} != nil {{ return s.{} }}",
|
|
1385
|
+
field_name, field_name
|
|
1386
|
+
)
|
|
1387
|
+
.unwrap();
|
|
1388
|
+
}
|
|
1389
|
+
writeln!(out, " return nil\n}}\n").unwrap();
|
|
1390
|
+
|
|
1391
|
+
// UnmarshalXML
|
|
1392
|
+
writeln!(
|
|
1393
|
+
out,
|
|
1394
|
+
"func (s *{}) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {{",
|
|
1395
|
+
struct_name
|
|
1396
|
+
)
|
|
1397
|
+
.unwrap();
|
|
1398
|
+
writeln!(out, " s.XMLName = start.Name").unwrap();
|
|
1399
|
+
writeln!(out, " var typeAttr *xml.Attr").unwrap();
|
|
1400
|
+
writeln!(out, " for _, attr := range start.Attr {{").unwrap();
|
|
1401
|
+
writeln!(out, " if (attr.Name.Local == \"type\" && (attr.Name.Space == \"http://www.w3.org/2001/XMLSchema-instance\" || attr.Name.Space == \"xsi\")) || attr.Name.Local == \"xsi:type\" {{").unwrap();
|
|
1402
|
+
writeln!(out, " typeAttr = &attr").unwrap();
|
|
1403
|
+
writeln!(out, " break").unwrap();
|
|
1404
|
+
writeln!(out, " }}").unwrap();
|
|
1405
|
+
writeln!(out, " }}").unwrap();
|
|
1406
|
+
writeln!(out, " if typeAttr == nil {{").unwrap();
|
|
1407
|
+
writeln!(
|
|
1408
|
+
out,
|
|
1409
|
+
" return fmt.Errorf(\"abstract type '{}' requires xsi:type naming a concrete derivation\")",
|
|
1410
|
+
struct_name
|
|
1411
|
+
)
|
|
1412
|
+
.unwrap();
|
|
1413
|
+
writeln!(out, " }}").unwrap();
|
|
1414
|
+
|
|
1415
|
+
if derive_fields.is_empty() {
|
|
1416
|
+
writeln!(
|
|
1417
|
+
out,
|
|
1418
|
+
" return fmt.Errorf(\"abstract type '{}' has no registered derivations; deserialize the concrete type directly (escape hatch)\")",
|
|
1419
|
+
struct_name
|
|
1420
|
+
)
|
|
1421
|
+
.unwrap();
|
|
1422
|
+
} else {
|
|
1423
|
+
writeln!(out, " localType := typeAttr.Value").unwrap();
|
|
1424
|
+
writeln!(
|
|
1425
|
+
out,
|
|
1426
|
+
" if idx := strings.Index(localType, \":\"); idx != -1 {{"
|
|
1427
|
+
)
|
|
1428
|
+
.unwrap();
|
|
1429
|
+
writeln!(out, " localType = localType[idx+1:]").unwrap();
|
|
1430
|
+
writeln!(out, " }}").unwrap();
|
|
1431
|
+
writeln!(out, " switch localType {{").unwrap();
|
|
1432
|
+
for (local, field_name, type_name) in &derive_fields {
|
|
1433
|
+
writeln!(out, " case {:?}:", local).unwrap();
|
|
1434
|
+
writeln!(out, " var concrete {}", type_name).unwrap();
|
|
1435
|
+
writeln!(
|
|
1436
|
+
out,
|
|
1437
|
+
" if err := d.DecodeElement(&concrete, &start); err != nil {{ return err }}"
|
|
1438
|
+
)
|
|
1439
|
+
.unwrap();
|
|
1440
|
+
writeln!(out, " s.{} = &concrete", field_name).unwrap();
|
|
1441
|
+
writeln!(
|
|
1442
|
+
out,
|
|
1443
|
+
" s.{} = concrete.{}",
|
|
1444
|
+
base_struct_name, base_struct_name
|
|
1445
|
+
)
|
|
1446
|
+
.unwrap();
|
|
1447
|
+
writeln!(out, " return nil").unwrap();
|
|
1448
|
+
}
|
|
1449
|
+
let known = derive_fields
|
|
1450
|
+
.iter()
|
|
1451
|
+
.map(|(local, _, _)| local.as_str())
|
|
1452
|
+
.collect::<Vec<_>>()
|
|
1453
|
+
.join(", ");
|
|
1454
|
+
writeln!(out, " default:").unwrap();
|
|
1455
|
+
writeln!(
|
|
1456
|
+
out,
|
|
1457
|
+
" return fmt.Errorf(\"xsi:type=%q does not match any known derivation of '{}' (known: {})\", typeAttr.Value)",
|
|
1458
|
+
struct_name, known
|
|
1459
|
+
)
|
|
1460
|
+
.unwrap();
|
|
1461
|
+
writeln!(out, " }}").unwrap();
|
|
1462
|
+
}
|
|
1463
|
+
writeln!(out, "}}\n").unwrap();
|
|
1464
|
+
|
|
1465
|
+
// MarshalXML
|
|
1466
|
+
writeln!(
|
|
1467
|
+
out,
|
|
1468
|
+
"func (s {}) MarshalXML(e *xml.Encoder, start xml.StartElement) error {{",
|
|
1469
|
+
struct_name
|
|
1470
|
+
)
|
|
1471
|
+
.unwrap();
|
|
1472
|
+
writeln!(
|
|
1473
|
+
out,
|
|
1474
|
+
" if s.XMLName.Local != \"\" {{ start.Name = s.XMLName }}"
|
|
1475
|
+
)
|
|
1476
|
+
.unwrap();
|
|
1477
|
+
for (local, field_name, _) in &derive_fields {
|
|
1478
|
+
writeln!(out, " if s.{} != nil {{", field_name).unwrap();
|
|
1479
|
+
writeln!(out, " hasXsiNs := false\n hasType := false").unwrap();
|
|
1480
|
+
writeln!(out, " for _, attr := range start.Attr {{").unwrap();
|
|
1481
|
+
writeln!(out, " if attr.Name.Local == \"xmlns:xsi\" || (attr.Name.Local == \"xsi\" && attr.Name.Space == \"xmlns\") {{ hasXsiNs = true }}").unwrap();
|
|
1482
|
+
writeln!(out, " if attr.Name.Local == \"xsi:type\" || (attr.Name.Local == \"type\" && attr.Name.Space == \"http://www.w3.org/2001/XMLSchema-instance\") {{ hasType = true }}").unwrap();
|
|
1483
|
+
writeln!(out, " }}").unwrap();
|
|
1484
|
+
writeln!(out, " if !hasXsiNs {{ start.Attr = append(start.Attr, xml.Attr{{Name: xml.Name{{Local: \"xmlns:xsi\"}}, Value: \"http://www.w3.org/2001/XMLSchema-instance\"}}) }}").unwrap();
|
|
1485
|
+
writeln!(out, " if !hasType {{ start.Attr = append(start.Attr, xml.Attr{{Name: xml.Name{{Local: \"xsi:type\"}}, Value: {:?}}}) }}", local).unwrap();
|
|
1486
|
+
writeln!(
|
|
1487
|
+
out,
|
|
1488
|
+
" return e.EncodeElement(s.{}, start)",
|
|
1489
|
+
field_name
|
|
1490
|
+
)
|
|
1491
|
+
.unwrap();
|
|
1492
|
+
writeln!(out, " }}").unwrap();
|
|
1493
|
+
}
|
|
1494
|
+
if derive_fields.is_empty() {
|
|
1495
|
+
writeln!(
|
|
1496
|
+
out,
|
|
1497
|
+
" return fmt.Errorf(\"abstract type '{}' has no registered derivations\")",
|
|
1498
|
+
struct_name
|
|
1499
|
+
)
|
|
1500
|
+
.unwrap();
|
|
1501
|
+
} else {
|
|
1502
|
+
writeln!(
|
|
1503
|
+
out,
|
|
1504
|
+
" return fmt.Errorf(\"cannot marshal abstract type '{}' without a concrete derivation\")",
|
|
1505
|
+
struct_name
|
|
1506
|
+
)
|
|
1507
|
+
.unwrap();
|
|
1508
|
+
}
|
|
1509
|
+
writeln!(out, "}}\n").unwrap();
|
|
1510
|
+
|
|
1511
|
+
// Validate()
|
|
1512
|
+
writeln!(out, "func (s {}) Validate() error {{", struct_name).unwrap();
|
|
1513
|
+
for (_, field_name, _) in &derive_fields {
|
|
1514
|
+
writeln!(
|
|
1515
|
+
out,
|
|
1516
|
+
" if s.{} != nil {{ return s.{}.Validate() }}",
|
|
1517
|
+
field_name, field_name
|
|
1518
|
+
)
|
|
1519
|
+
.unwrap();
|
|
1520
|
+
}
|
|
1521
|
+
if derive_fields.is_empty() {
|
|
1522
|
+
writeln!(
|
|
1523
|
+
out,
|
|
1524
|
+
" return fmt.Errorf(\"abstract type '{}' has no registered derivations\")",
|
|
1525
|
+
struct_name
|
|
1526
|
+
)
|
|
1527
|
+
.unwrap();
|
|
1528
|
+
} else {
|
|
1529
|
+
writeln!(
|
|
1530
|
+
out,
|
|
1531
|
+
" return fmt.Errorf(\"abstract type '{}' requires a concrete derivation\")",
|
|
1532
|
+
struct_name
|
|
1533
|
+
)
|
|
1534
|
+
.unwrap();
|
|
1535
|
+
}
|
|
1536
|
+
writeln!(out, "}}\n").unwrap();
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1247
1539
|
fn emit_facet_checks(
|
|
1248
1540
|
&self,
|
|
1249
1541
|
out: &mut String,
|
|
@@ -1324,3 +1616,34 @@ impl GoCodegen {
|
|
|
1324
1616
|
}
|
|
1325
1617
|
}
|
|
1326
1618
|
}
|
|
1619
|
+
|
|
1620
|
+
fn derives_from(ir: &SchemaIR, d: &StructDef, base: &QName) -> bool {
|
|
1621
|
+
let mut seen: HashSet<QName> = HashSet::new();
|
|
1622
|
+
let mut cur = d.base_type.as_ref();
|
|
1623
|
+
while let Some(q) = cur {
|
|
1624
|
+
if q == base {
|
|
1625
|
+
return true;
|
|
1626
|
+
}
|
|
1627
|
+
if !seen.insert(q.clone()) {
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
cur = match ir.types.get(q) {
|
|
1631
|
+
Some(TypeDef::Struct(b)) => b.base_type.as_ref(),
|
|
1632
|
+
_ => None,
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
false
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
fn concrete_derivations<'a>(s: &'a StructDef, ir: &'a SchemaIR) -> Vec<&'a StructDef> {
|
|
1639
|
+
let mut result = Vec::new();
|
|
1640
|
+
for type_def in ir.types.values() {
|
|
1641
|
+
if let TypeDef::Struct(d) = type_def {
|
|
1642
|
+
if !d.is_abstract && d.qname != s.qname && derives_from(ir, d, &s.qname) {
|
|
1643
|
+
result.push(d);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
result.sort_by(|a, b| a.qname.local.cmp(&b.qname.local));
|
|
1648
|
+
result
|
|
1649
|
+
}
|