polyxml 0.33.2__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.2 → polyxml-0.33.3}/Cargo.lock +6 -6
- {polyxml-0.33.2 → polyxml-0.33.3}/Cargo.toml +1 -1
- {polyxml-0.33.2 → polyxml-0.33.3}/PKG-INFO +1 -1
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/go/mod.rs +307 -10
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_go_codegen.rs +129 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/pyproject.toml +1 -1
- {polyxml-0.33.2 → polyxml-0.33.3}/README.md +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/ir/chunker.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/parser.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/schema.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/schema_parser/mod.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/serializer.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_any_attribute.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_any_element.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/src/lib.rs +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/python/polyxml/__init__.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.33.2 → polyxml-0.33.3}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.33.2 → 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\"");
|
|
@@ -913,6 +912,11 @@ impl GoCodegen {
|
|
|
913
912
|
}
|
|
914
913
|
|
|
915
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
|
+
|
|
916
920
|
let struct_name = type_ident(&s.qname);
|
|
917
921
|
if let Some(ref doc) = s.documentation {
|
|
918
922
|
for line in doc.lines() {
|
|
@@ -945,9 +949,13 @@ impl GoCodegen {
|
|
|
945
949
|
// Struct composition / inheritance if base struct exists
|
|
946
950
|
let mut simple_content_base: Option<String> = None;
|
|
947
951
|
if let Some(ref base_qname) = s.base_type {
|
|
948
|
-
if
|
|
952
|
+
if let Some(TypeDef::Struct(base_s)) = ir.types.get(base_qname) {
|
|
949
953
|
let base_name = type_ident(base_qname);
|
|
950
|
-
|
|
954
|
+
if base_s.is_abstract {
|
|
955
|
+
writeln!(out, " {}Base", base_name).unwrap();
|
|
956
|
+
} else {
|
|
957
|
+
writeln!(out, " {}", base_name).unwrap();
|
|
958
|
+
}
|
|
951
959
|
} else if let Some(prim) = PrimitiveType::from_xsd_name(&base_qname.local) {
|
|
952
960
|
simple_content_base = Some(self.context.map_primitive(prim).to_string());
|
|
953
961
|
} else if let Some(TypeDef::Simple(st)) = ir.types.get(base_qname) {
|
|
@@ -1270,6 +1278,264 @@ impl GoCodegen {
|
|
|
1270
1278
|
writeln!(out, "}}\n").unwrap();
|
|
1271
1279
|
}
|
|
1272
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
|
+
|
|
1273
1539
|
fn emit_facet_checks(
|
|
1274
1540
|
&self,
|
|
1275
1541
|
out: &mut String,
|
|
@@ -1350,3 +1616,34 @@ impl GoCodegen {
|
|
|
1350
1616
|
}
|
|
1351
1617
|
}
|
|
1352
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
|
+
}
|
|
@@ -837,3 +837,132 @@ fn test_go_any_attribute_codegen() {
|
|
|
837
837
|
|
|
838
838
|
assert!(code.contains("AnyAttribute []xml.Attr `xml:\",any,attr\" json:\"-\"`"));
|
|
839
839
|
}
|
|
840
|
+
|
|
841
|
+
#[test]
|
|
842
|
+
fn test_go_abstract_xsi_type_dispatch() {
|
|
843
|
+
let xsd = r#"<?xml version="1.0" encoding="UTF-8"?>
|
|
844
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:audit:abstract" xmlns:t="urn:audit:abstract" elementFormDefault="qualified">
|
|
845
|
+
<xs:complexType name="AbstractDocument" abstract="true">
|
|
846
|
+
<xs:sequence>
|
|
847
|
+
<xs:element name="Id" type="xs:string"/>
|
|
848
|
+
</xs:sequence>
|
|
849
|
+
</xs:complexType>
|
|
850
|
+
|
|
851
|
+
<xs:complexType name="InvoiceDocument">
|
|
852
|
+
<xs:complexContent>
|
|
853
|
+
<xs:extension base="t:AbstractDocument">
|
|
854
|
+
<xs:sequence>
|
|
855
|
+
<xs:element name="Amount" type="xs:decimal"/>
|
|
856
|
+
</xs:sequence>
|
|
857
|
+
</xs:extension>
|
|
858
|
+
</xs:complexContent>
|
|
859
|
+
</xs:complexType>
|
|
860
|
+
|
|
861
|
+
<xs:complexType name="ReceiptDocument">
|
|
862
|
+
<xs:complexContent>
|
|
863
|
+
<xs:extension base="t:AbstractDocument">
|
|
864
|
+
<xs:sequence>
|
|
865
|
+
<xs:element name="Store" type="xs:string"/>
|
|
866
|
+
</xs:sequence>
|
|
867
|
+
</xs:extension>
|
|
868
|
+
</xs:complexContent>
|
|
869
|
+
</xs:complexType>
|
|
870
|
+
|
|
871
|
+
<xs:element name="Document" type="t:AbstractDocument"/>
|
|
872
|
+
</xs:schema>"#;
|
|
873
|
+
|
|
874
|
+
let ir = XsdParser::new().parse_str(xsd).expect("parse failed");
|
|
875
|
+
let codegen = GoCodegen::new(GoOptions::default());
|
|
876
|
+
let code = codegen.generate_module(&ir);
|
|
877
|
+
|
|
878
|
+
assert!(code.contains("type AbstractDocumentBase struct"));
|
|
879
|
+
assert!(code.contains("type AbstractDocument struct"));
|
|
880
|
+
assert!(code.contains("InvoiceDocument *InvoiceDocument"));
|
|
881
|
+
assert!(code.contains("ReceiptDocument *ReceiptDocument"));
|
|
882
|
+
assert!(code.contains("func (s AbstractDocument) Selected() string"));
|
|
883
|
+
assert!(code.contains("func (s AbstractDocument) Value() any"));
|
|
884
|
+
assert!(code.contains("func (s *AbstractDocument) UnmarshalXML"));
|
|
885
|
+
assert!(code.contains("func (s AbstractDocument) MarshalXML"));
|
|
886
|
+
|
|
887
|
+
if Command::new("go").arg("version").output().is_err() {
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
let dir = tempdir().unwrap();
|
|
892
|
+
fs::write(
|
|
893
|
+
dir.path().join("go.mod"),
|
|
894
|
+
"module abstract_test\n\ngo 1.22\n",
|
|
895
|
+
)
|
|
896
|
+
.unwrap();
|
|
897
|
+
fs::write(dir.path().join("models.go"), &code).unwrap();
|
|
898
|
+
fs::write(
|
|
899
|
+
dir.path().join("models_test.go"),
|
|
900
|
+
r#"package models
|
|
901
|
+
|
|
902
|
+
import (
|
|
903
|
+
"encoding/xml"
|
|
904
|
+
"strings"
|
|
905
|
+
"testing"
|
|
906
|
+
)
|
|
907
|
+
|
|
908
|
+
func TestAbstractDocumentRoundTrip(t *testing.T) {
|
|
909
|
+
inputXml := `<Document xmlns="urn:audit:abstract" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="InvoiceDocument"><Id>INV-001</Id><Amount>199.99</Amount></Document>`
|
|
910
|
+
var doc Document
|
|
911
|
+
if err := xml.Unmarshal([]byte(inputXml), &doc); err != nil {
|
|
912
|
+
t.Fatalf("Unmarshal failed: %v", err)
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
if doc.Selected() != "InvoiceDocument" {
|
|
916
|
+
t.Fatalf("expected Selected() to be InvoiceDocument, got %q", doc.Selected())
|
|
917
|
+
}
|
|
918
|
+
if doc.InvoiceDocument == nil {
|
|
919
|
+
t.Fatalf("InvoiceDocument is nil")
|
|
920
|
+
}
|
|
921
|
+
if doc.InvoiceDocument.ID != "INV-001" {
|
|
922
|
+
t.Fatalf("expected ID 'INV-001', got %q", doc.InvoiceDocument.ID)
|
|
923
|
+
}
|
|
924
|
+
if doc.InvoiceDocument.Amount != 199.99 {
|
|
925
|
+
t.Fatalf("expected Amount 199.99, got %v", doc.InvoiceDocument.Amount)
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
marshaled, err := xml.Marshal(&doc)
|
|
929
|
+
if err != nil {
|
|
930
|
+
t.Fatalf("Marshal failed: %v", err)
|
|
931
|
+
}
|
|
932
|
+
marshaledStr := string(marshaled)
|
|
933
|
+
if !strings.Contains(marshaledStr, `xsi:type="InvoiceDocument"`) {
|
|
934
|
+
t.Fatalf("marshaled XML missing xsi:type: %s", marshaledStr)
|
|
935
|
+
}
|
|
936
|
+
if !strings.Contains(marshaledStr, `Amount`) {
|
|
937
|
+
t.Fatalf("marshaled XML missing Amount element: %s", marshaledStr)
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// Missing xsi:type should fail
|
|
941
|
+
var missingDoc Document
|
|
942
|
+
if err := xml.Unmarshal([]byte(`<Document xmlns="urn:audit:abstract"><Id>INV-001</Id></Document>`), &missingDoc); err == nil {
|
|
943
|
+
t.Fatalf("expected error unmarshaling abstract type without xsi:type, got nil")
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// Unknown xsi:type should fail
|
|
947
|
+
var unknownDoc Document
|
|
948
|
+
if err := xml.Unmarshal([]byte(`<Document xmlns="urn:audit:abstract" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="UnknownDoc"><Id>INV-001</Id></Document>`), &unknownDoc); err == nil {
|
|
949
|
+
t.Fatalf("expected error unmarshaling unknown xsi:type, got nil")
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
"#,
|
|
953
|
+
)
|
|
954
|
+
.unwrap();
|
|
955
|
+
|
|
956
|
+
let output = Command::new("go")
|
|
957
|
+
.args(["test", "-v", "./..."])
|
|
958
|
+
.current_dir(dir.path())
|
|
959
|
+
.output()
|
|
960
|
+
.expect("go test failed to execute");
|
|
961
|
+
|
|
962
|
+
assert!(
|
|
963
|
+
output.status.success(),
|
|
964
|
+
"go test failed: stdout:\n{}\nstderr:\n{}",
|
|
965
|
+
String::from_utf8_lossy(&output.stdout),
|
|
966
|
+
String::from_utf8_lossy(&output.stderr)
|
|
967
|
+
);
|
|
968
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{polyxml-0.33.2 → polyxml-0.33.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
|