polyxml 0.33.0__tar.gz → 0.33.2__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.
Files changed (75) hide show
  1. {polyxml-0.33.0 → polyxml-0.33.2}/Cargo.lock +20 -20
  2. {polyxml-0.33.0 → polyxml-0.33.2}/Cargo.toml +1 -1
  3. {polyxml-0.33.0 → polyxml-0.33.2}/PKG-INFO +1 -1
  4. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/csharp/mod.rs +28 -8
  5. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/go/mod.rs +79 -29
  6. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/python/mod.rs +88 -20
  7. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/rust/mod.rs +31 -8
  8. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/parser.rs +216 -0
  9. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/schema.rs +16 -1
  10. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/schema_parser/mod.rs +98 -7
  11. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/serializer.rs +118 -0
  12. polyxml-0.33.2/crates/polyxml-core/tests/test_any_attribute.rs +96 -0
  13. polyxml-0.33.2/crates/polyxml-core/tests/test_any_element.rs +154 -0
  14. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_csharp_codegen.rs +138 -0
  15. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_go_codegen.rs +70 -0
  16. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_python_codegen.rs +112 -0
  17. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_rust_codegen.rs +29 -0
  18. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/src/lib.rs +142 -10
  19. {polyxml-0.33.0 → polyxml-0.33.2}/pyproject.toml +1 -1
  20. {polyxml-0.33.0 → polyxml-0.33.2}/python/polyxml/__init__.py +12 -1
  21. {polyxml-0.33.0 → polyxml-0.33.2}/README.md +0 -0
  22. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/Cargo.toml +0 -0
  23. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/README.md +0 -0
  24. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
  25. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
  26. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
  27. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
  28. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
  29. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
  30. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
  31. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/mod.rs +0 -0
  32. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
  33. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
  34. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/converters.rs +0 -0
  35. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/error.rs +0 -0
  36. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/ir/chunker.rs +0 -0
  37. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/ir/mod.rs +0 -0
  38. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
  39. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/json.rs +0 -0
  40. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/lib.rs +0 -0
  41. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/transcoder.rs +0 -0
  42. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/src/value.rs +0 -0
  43. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
  44. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
  45. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
  46. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
  47. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_conformance.rs +0 -0
  48. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_core.rs +0 -0
  49. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
  50. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
  51. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_json.rs +0 -0
  52. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
  53. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
  54. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
  55. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
  56. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
  57. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
  58. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_security.rs +0 -0
  59. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
  60. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
  61. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
  62. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
  63. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/Cargo.toml +0 -0
  64. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/README.md +0 -0
  65. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
  66. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/tests/test_conformance.py +0 -0
  67. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/tests/test_generated_models.py +0 -0
  68. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/tests/test_json.py +0 -0
  69. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
  70. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/tests/test_polyxml.py +0 -0
  71. {polyxml-0.33.0 → polyxml-0.33.2}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
  72. {polyxml-0.33.0 → polyxml-0.33.2}/python/polyxml/AGENT_GUIDE.md +0 -0
  73. {polyxml-0.33.0 → polyxml-0.33.2}/python/polyxml/compat/__init__.py +0 -0
  74. {polyxml-0.33.0 → polyxml-0.33.2}/python/polyxml/compat/xsdata.py +0 -0
  75. {polyxml-0.33.0 → polyxml-0.33.2}/python/polyxml/py.typed +0 -0
@@ -608,7 +608,7 @@ dependencies = [
608
608
 
609
609
  [[package]]
610
610
  name = "polyxml"
611
- version = "0.33.0"
611
+ version = "0.33.2"
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.0"
632
+ version = "0.33.2"
633
633
  dependencies = [
634
634
  "polyxml",
635
635
  ]
636
636
 
637
637
  [[package]]
638
638
  name = "polyxml-cli"
639
- version = "0.33.0"
639
+ version = "0.33.2"
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.0"
653
+ version = "0.33.2"
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.0"
663
+ version = "0.33.2"
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.0"
673
+ version = "0.33.2"
674
674
  dependencies = [
675
675
  "polyxml",
676
676
  "quick-xml",
@@ -913,9 +913,9 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
913
913
 
914
914
  [[package]]
915
915
  name = "smallvec"
916
- version = "1.16.1"
916
+ version = "1.16.2"
917
917
  source = "registry+https://github.com/rust-lang/crates.io-index"
918
- checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891"
918
+ checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e"
919
919
 
920
920
  [[package]]
921
921
  name = "strsim"
@@ -966,18 +966,18 @@ dependencies = [
966
966
 
967
967
  [[package]]
968
968
  name = "thiserror"
969
- version = "2.0.20"
969
+ version = "2.0.21"
970
970
  source = "registry+https://github.com/rust-lang/crates.io-index"
971
- checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
971
+ checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
972
972
  dependencies = [
973
973
  "thiserror-impl",
974
974
  ]
975
975
 
976
976
  [[package]]
977
977
  name = "thiserror-impl"
978
- version = "2.0.20"
978
+ version = "2.0.21"
979
979
  source = "registry+https://github.com/rust-lang/crates.io-index"
980
- checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
980
+ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
981
981
  dependencies = [
982
982
  "proc-macro2",
983
983
  "quote",
@@ -1063,9 +1063,9 @@ dependencies = [
1063
1063
 
1064
1064
  [[package]]
1065
1065
  name = "wasm-bindgen"
1066
- version = "0.2.128"
1066
+ version = "0.2.129"
1067
1067
  source = "registry+https://github.com/rust-lang/crates.io-index"
1068
- checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
1068
+ checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409"
1069
1069
  dependencies = [
1070
1070
  "cfg-if",
1071
1071
  "once_cell",
@@ -1076,9 +1076,9 @@ dependencies = [
1076
1076
 
1077
1077
  [[package]]
1078
1078
  name = "wasm-bindgen-macro"
1079
- version = "0.2.128"
1079
+ version = "0.2.129"
1080
1080
  source = "registry+https://github.com/rust-lang/crates.io-index"
1081
- checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
1081
+ checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535"
1082
1082
  dependencies = [
1083
1083
  "quote",
1084
1084
  "wasm-bindgen-macro-support",
@@ -1086,9 +1086,9 @@ dependencies = [
1086
1086
 
1087
1087
  [[package]]
1088
1088
  name = "wasm-bindgen-macro-support"
1089
- version = "0.2.128"
1089
+ version = "0.2.129"
1090
1090
  source = "registry+https://github.com/rust-lang/crates.io-index"
1091
- checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
1091
+ checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7"
1092
1092
  dependencies = [
1093
1093
  "bumpalo",
1094
1094
  "proc-macro2",
@@ -1099,9 +1099,9 @@ dependencies = [
1099
1099
 
1100
1100
  [[package]]
1101
1101
  name = "wasm-bindgen-shared"
1102
- version = "0.2.128"
1102
+ version = "0.2.129"
1103
1103
  source = "registry+https://github.com/rust-lang/crates.io-index"
1104
- checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
1104
+ checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6"
1105
1105
  dependencies = [
1106
1106
  "unicode-ident",
1107
1107
  ]
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/polyxml-core", "crates/polyxml-python"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.33.0"
6
+ version = "0.33.2"
7
7
  edition = "2021"
8
8
  rust-version = "1.80"
9
9
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyxml
3
- Version: 0.33.0
3
+ Version: 0.33.2
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -307,6 +307,7 @@ impl CSharpCodegen {
307
307
  writeln!(out, "using System.Text.RegularExpressions;").unwrap();
308
308
  }
309
309
  if self.options.emit_xml_attributes {
310
+ writeln!(out, "using System.Xml;").unwrap();
310
311
  writeln!(out, "using System.Xml.Serialization;").unwrap();
311
312
  }
312
313
  if self.options.emit_json_attributes || self.options.emit_source_gen {
@@ -582,7 +583,7 @@ impl CSharpCodegen {
582
583
  }
583
584
  writeln!(
584
585
  out,
585
- "{}public sealed record {}([property: XmlText] {} Value) : IValidatableObject",
586
+ "{}public record {}([property: XmlText] {} Value) : IValidatableObject",
586
587
  indent, type_name, base_type
587
588
  )
588
589
  .unwrap();
@@ -819,6 +820,16 @@ impl CSharpCodegen {
819
820
  TypeRef::Primitive(PrimitiveType::Date)
820
821
  ) {
821
822
  "item.Value.ToString(\"yyyy-MM-dd\", System.Globalization.CultureInfo.InvariantCulture)".to_string()
823
+ } else if matches!(
824
+ super::primitive_base(&branch.type_ref, ir),
825
+ TypeRef::Primitive(PrimitiveType::DateTime)
826
+ ) {
827
+ "System.Xml.XmlConvert.ToString(item.Value)".to_string()
828
+ } else if matches!(
829
+ super::primitive_base(&branch.type_ref, ir),
830
+ TypeRef::Primitive(PrimitiveType::Time)
831
+ ) {
832
+ "item.Value.ToString(\"HH:mm:ssK\", System.Globalization.CultureInfo.InvariantCulture)".to_string()
822
833
  } else {
823
834
  match &branch.type_ref {
824
835
  TypeRef::Named(qname) if matches!(ir.types.get(qname), Some(TypeDef::Enum(_))) => "item.Value.ToXmlValue()".to_string(),
@@ -1039,7 +1050,7 @@ impl CSharpCodegen {
1039
1050
  );
1040
1051
  }
1041
1052
  if self.options.emit_validation {
1042
- self.emit_struct_validator(out, s, &prop_names, indent);
1053
+ self.emit_struct_validator(out, s, ir, &prop_names, indent);
1043
1054
  }
1044
1055
  writeln!(out, "{}}}\n", indent).unwrap();
1045
1056
  return;
@@ -1093,7 +1104,7 @@ impl CSharpCodegen {
1093
1104
  .unwrap();
1094
1105
  }
1095
1106
  if self.options.emit_validation {
1096
- self.emit_struct_validator(out, s, &prop_names, indent);
1107
+ self.emit_struct_validator(out, s, ir, &prop_names, indent);
1097
1108
  }
1098
1109
  writeln!(out, "{}}}\n", indent).unwrap();
1099
1110
  return;
@@ -1109,7 +1120,7 @@ impl CSharpCodegen {
1109
1120
  )
1110
1121
  .unwrap();
1111
1122
  writeln!(out, "{}{{", indent).unwrap();
1112
- self.emit_struct_validator(out, s, &prop_names, indent);
1123
+ self.emit_struct_validator(out, s, ir, &prop_names, indent);
1113
1124
  writeln!(out, "{}}}", indent).unwrap();
1114
1125
  } else {
1115
1126
  writeln!(
@@ -1182,7 +1193,7 @@ impl CSharpCodegen {
1182
1193
 
1183
1194
  // IValidatableObject implementation
1184
1195
  if self.options.emit_validation {
1185
- self.emit_struct_validator(out, s, &prop_names, indent);
1196
+ self.emit_struct_validator(out, s, ir, &prop_names, indent);
1186
1197
  }
1187
1198
 
1188
1199
  writeln!(out, "{}}}\n", indent).unwrap();
@@ -1221,17 +1232,23 @@ impl CSharpCodegen {
1221
1232
  &self,
1222
1233
  out: &mut String,
1223
1234
  s: &StructDef,
1235
+ ir: &SchemaIR,
1224
1236
  prop_names: &[String],
1225
1237
  indent: &str,
1226
1238
  ) {
1227
1239
  let _struct_name = type_ident(&s.qname);
1240
+ let has_struct_base = s
1241
+ .base_type
1242
+ .as_ref()
1243
+ .map(|b| matches!(ir.types.get(b), Some(TypeDef::Struct(_))))
1244
+ .unwrap_or(false);
1228
1245
  let new_kw = if !self.options.use_records {
1229
- if s.base_type.is_some() {
1246
+ if has_struct_base {
1230
1247
  "override "
1231
1248
  } else {
1232
1249
  "virtual "
1233
1250
  }
1234
- } else if s.base_type.is_some() {
1251
+ } else if has_struct_base {
1235
1252
  "new "
1236
1253
  } else {
1237
1254
  ""
@@ -1244,7 +1261,7 @@ impl CSharpCodegen {
1244
1261
  .unwrap();
1245
1262
  writeln!(out, "{} {{", indent).unwrap();
1246
1263
 
1247
- if !self.options.use_records && s.base_type.is_some() {
1264
+ if !self.options.use_records && has_struct_base {
1248
1265
  writeln!(out, "{} foreach (var result in base.Validate(validationContext)) yield return result;", indent).unwrap();
1249
1266
  }
1250
1267
  let mut has_checks = false;
@@ -1345,6 +1362,9 @@ impl CSharpCodegen {
1345
1362
  }
1346
1363
 
1347
1364
  fn map_field_type(&self, f: &FieldDef, ir: &SchemaIR) -> String {
1365
+ if f.kind == FieldKind::AnyAttribute {
1366
+ return "System.Xml.XmlAttribute[]?".to_string();
1367
+ }
1348
1368
  let base_type = match &f.type_ref {
1349
1369
  TypeRef::Primitive(p) => self.context.map_primitive(*p).to_string(),
1350
1370
  TypeRef::Named(qn) => {
@@ -273,14 +273,12 @@ impl GoCodegen {
273
273
  }));
274
274
  let mut has_fmt = has_patterns;
275
275
  let mut has_io = false;
276
- let mut has_xml = self.options.emit_xml_tags;
277
276
 
278
277
  // Check types for time.Time
279
278
  for type_def in ir.emitted_types() {
280
279
  match type_def {
281
280
  TypeDef::Struct(s) => {
282
281
  if s.is_mixed && self.options.emit_xml_tags {
283
- has_xml = true;
284
282
  has_fmt = true;
285
283
  has_io = true;
286
284
  }
@@ -310,11 +308,9 @@ impl GoCodegen {
310
308
  if self.options.validate_choice_exclusivity && !u.is_lexical() {
311
309
  has_fmt = true;
312
310
  has_io = true;
313
- has_xml = true;
314
311
  }
315
312
  if u.is_lexical() {
316
313
  has_fmt = true;
317
- has_xml = true;
318
314
  }
319
315
  }
320
316
  TypeDef::Simple(st) => {
@@ -354,7 +350,7 @@ impl GoCodegen {
354
350
  writeln!(out, "package {}\n", pkg).unwrap();
355
351
 
356
352
  let mut imports = Vec::new();
357
- if has_xml {
353
+ if body.contains("xml.") {
358
354
  imports.push("\"encoding/xml\"");
359
355
  }
360
356
  if self.options.emit_xml_tags
@@ -451,6 +447,14 @@ impl GoCodegen {
451
447
  self.emit_struct(out, s, ir);
452
448
  }
453
449
  }
450
+
451
+ let has_any_element = ir.emitted_types().any(|t| match t {
452
+ TypeDef::Struct(s) => s.fields.iter().any(|f| f.kind == FieldKind::Any),
453
+ _ => false,
454
+ });
455
+ if has_any_element {
456
+ 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");
457
+ }
454
458
  }
455
459
 
456
460
  fn emit_simple_type(&self, out: &mut String, simple: &SimpleTypeDef, ir: &SchemaIR) {
@@ -813,6 +817,12 @@ impl GoCodegen {
813
817
  };
814
818
  if matches!(base, TypeRef::Primitive(PrimitiveType::Date)) {
815
819
  let _ = writeln!(out, " if parsed, err := time.Parse(\"2006-01-02\", value); err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", mapped, field);
820
+ } else if matches!(base, TypeRef::Primitive(PrimitiveType::DateTime)) {
821
+ let _ = writeln!(out, " if parsed, err := time.Parse(time.RFC3339, value); err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", mapped, field);
822
+ let _ = writeln!(out, " if parsed, err := time.Parse(\"2006-01-02T15:04:05\", value); err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", mapped, field);
823
+ } else if matches!(base, TypeRef::Primitive(PrimitiveType::Time)) {
824
+ let _ = writeln!(out, " if parsed, err := time.Parse(\"15:04:05Z07:00\", value); err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", mapped, field);
825
+ let _ = writeln!(out, " if parsed, err := time.Parse(\"15:04:05\", value); err == nil {{ v := {}(parsed); c.{} = &v; return nil }}", mapped, field);
816
826
  } else if let Some(kind) = numeric {
817
827
  let parse = match kind {
818
828
  "signed" => "strconv.ParseInt(value, 10, 64)",
@@ -880,6 +890,16 @@ impl GoCodegen {
880
890
  TypeRef::Primitive(PrimitiveType::Date)
881
891
  ) {
882
892
  format!("c.{}.Format(\"2006-01-02\")", field)
893
+ } else if matches!(
894
+ super::primitive_base(&branch.type_ref, ir),
895
+ TypeRef::Primitive(PrimitiveType::DateTime)
896
+ ) {
897
+ format!("c.{}.Format(time.RFC3339)", field)
898
+ } else if matches!(
899
+ super::primitive_base(&branch.type_ref, ir),
900
+ TypeRef::Primitive(PrimitiveType::Time)
901
+ ) {
902
+ format!("c.{}.Format(\"15:04:05Z07:00\")", field)
883
903
  } else {
884
904
  format!("fmt.Sprint(*c.{})", field)
885
905
  };
@@ -1089,6 +1109,18 @@ impl GoCodegen {
1089
1109
  }
1090
1110
 
1091
1111
  fn resolve_field_type(&self, f: &FieldDef) -> String {
1112
+ if f.kind == FieldKind::AnyAttribute {
1113
+ return "[]xml.Attr".to_string();
1114
+ }
1115
+ if f.kind == FieldKind::Any {
1116
+ if f.cardinality.is_list() {
1117
+ return "[]AnyElement".to_string();
1118
+ } else if f.is_cycle_cut || f.cardinality.is_optional() || f.nillable {
1119
+ return "*AnyElement".to_string();
1120
+ } else {
1121
+ return "AnyElement".to_string();
1122
+ }
1123
+ }
1092
1124
  let base_type = self.context.map_type_ref(&f.type_ref);
1093
1125
 
1094
1126
  if f.cardinality.is_list() {
@@ -1134,32 +1166,50 @@ impl GoCodegen {
1134
1166
  }
1135
1167
 
1136
1168
  if self.options.emit_json_tags || self.options.backend == GoBackend::Sonic {
1137
- let is_opt = f.cardinality.is_optional() || f.nillable;
1138
- let raw_json_name = if f.kind == FieldKind::Text {
1139
- "value".to_string()
1140
- } else if f.xml_name.is_empty() {
1141
- f.name.clone()
1169
+ if f.kind == FieldKind::AnyAttribute {
1170
+ if self.options.emit_json_tags {
1171
+ parts.push("json:\"-\"".to_string());
1172
+ }
1173
+ if self.options.backend == GoBackend::Sonic {
1174
+ parts.push("sonic:\"-\"".to_string());
1175
+ }
1176
+ } else if f.kind == FieldKind::Any {
1177
+ let is_opt = f.cardinality.is_optional() || f.nillable;
1178
+ let tag = if is_opt { "any,omitempty" } else { "any" };
1179
+ if self.options.emit_json_tags {
1180
+ parts.push(format!("json:\"{}\"", tag));
1181
+ }
1182
+ if self.options.backend == GoBackend::Sonic {
1183
+ parts.push(format!("sonic:\"{}\"", tag));
1184
+ }
1142
1185
  } else {
1143
- f.xml_name.clone()
1144
- };
1145
- let mut json_name = raw_json_name.clone();
1146
- let mut counter = 2;
1147
- while seen_json.contains(&json_name) {
1148
- json_name = format!("{}_{}", raw_json_name, counter);
1149
- counter += 1;
1150
- }
1151
- seen_json.insert(json_name.clone());
1186
+ let is_opt = f.cardinality.is_optional() || f.nillable;
1187
+ let raw_json_name = if f.kind == FieldKind::Text {
1188
+ "value".to_string()
1189
+ } else if f.xml_name.is_empty() {
1190
+ f.name.clone()
1191
+ } else {
1192
+ f.xml_name.clone()
1193
+ };
1194
+ let mut json_name = raw_json_name.clone();
1195
+ let mut counter = 2;
1196
+ while seen_json.contains(&json_name) {
1197
+ json_name = format!("{}_{}", raw_json_name, counter);
1198
+ counter += 1;
1199
+ }
1200
+ seen_json.insert(json_name.clone());
1152
1201
 
1153
- let json_val = if is_opt {
1154
- format!("{},omitempty", json_name)
1155
- } else {
1156
- json_name
1157
- };
1158
- if self.options.emit_json_tags {
1159
- parts.push(format!("json:\"{}\"", json_val));
1160
- }
1161
- if self.options.backend == GoBackend::Sonic {
1162
- parts.push(format!("sonic:\"{}\"", json_val));
1202
+ let json_val = if is_opt {
1203
+ format!("{},omitempty", json_name)
1204
+ } else {
1205
+ json_name
1206
+ };
1207
+ if self.options.emit_json_tags {
1208
+ parts.push(format!("json:\"{}\"", json_val));
1209
+ }
1210
+ if self.options.backend == GoBackend::Sonic {
1211
+ parts.push(format!("sonic:\"{}\"", json_val));
1212
+ }
1163
1213
  }
1164
1214
  }
1165
1215
 
@@ -638,7 +638,11 @@ impl PythonCodegen {
638
638
  if has_body {
639
639
  out.push('\n');
640
640
  }
641
- out.push_str(" class Meta:\n");
641
+ if let Some(ref base_name) = struct_base {
642
+ let _ = writeln!(out, " class Meta({}.Meta):", base_name);
643
+ } else {
644
+ out.push_str(" class Meta:\n");
645
+ }
642
646
  let _ = writeln!(out, " name = \"{}\"", s.qname.local);
643
647
  if let Some(ref ns) = s.qname.namespace {
644
648
  let _ = writeln!(out, " namespace = \"{}\"", ns);
@@ -692,7 +696,7 @@ impl PythonCodegen {
692
696
  let mut seen_fields = HashSet::new();
693
697
  for field in &s.fields {
694
698
  let py_field_name = self.unique_field_name(&field.name, &mut seen_fields);
695
- self.emit_field(out, field, &py_field_name);
699
+ self.emit_field(out, field, &py_field_name, ir);
696
700
  }
697
701
  has_body = true;
698
702
  }
@@ -754,7 +758,7 @@ impl PythonCodegen {
754
758
  candidate
755
759
  }
756
760
 
757
- fn emit_field(&self, out: &mut String, field: &FieldDef, py_name: &str) {
761
+ fn emit_field(&self, out: &mut String, field: &FieldDef, py_name: &str, ir: &SchemaIR) {
758
762
  let is_list = field.cardinality.is_list() || field.type_ref.is_list();
759
763
  let unwrapped_ref = match &field.type_ref {
760
764
  TypeRef::List(inner) => inner.as_ref(),
@@ -765,10 +769,10 @@ impl PythonCodegen {
765
769
 
766
770
  let (field_type, field_call) = match self.options.backend {
767
771
  PythonBackend::Dataclass | PythonBackend::Aot => {
768
- self.format_dataclass_field(field, is_list, &inner_type, &meta_dict)
772
+ self.format_dataclass_field(field, is_list, &inner_type, &meta_dict, ir)
769
773
  }
770
774
  PythonBackend::Pydantic => {
771
- self.format_pydantic_field(field, py_name, is_list, &inner_type, &meta_dict)
775
+ self.format_pydantic_field(field, py_name, is_list, &inner_type, &meta_dict, ir)
772
776
  }
773
777
  };
774
778
 
@@ -785,7 +789,27 @@ impl PythonCodegen {
785
789
  is_list: bool,
786
790
  base_type: &str,
787
791
  meta_dict: &str,
792
+ ir: &SchemaIR,
788
793
  ) -> (String, String) {
794
+ let simple_content = match &field.type_ref {
795
+ TypeRef::Named(qname) => match ir.find_type(qname) {
796
+ Some(TypeDef::Struct(s)) => s
797
+ .fields
798
+ .iter()
799
+ .find(|f| f.kind == FieldKind::Text)
800
+ .map(|tf| (tf.name.clone(), tf.type_ref.clone())),
801
+ _ => None,
802
+ },
803
+ _ => None,
804
+ };
805
+
806
+ if field.kind == FieldKind::AnyAttribute {
807
+ return (
808
+ "dict[str, str]".to_string(),
809
+ format!("field(default_factory=dict, metadata={})", meta_dict),
810
+ );
811
+ }
812
+
789
813
  if is_list {
790
814
  (
791
815
  format!("list[{}]", base_type),
@@ -793,7 +817,7 @@ impl PythonCodegen {
793
817
  )
794
818
  } else if field.cardinality.is_optional() || field.nillable {
795
819
  if let Some(ref def) = field.default_value {
796
- let py_val = self.format_default_value(def, &field.type_ref);
820
+ let py_val = self.format_default_value(def, &field.type_ref, ir);
797
821
  (
798
822
  format!("{} | None", base_type),
799
823
  format!("field(default={}, metadata={})", py_val, meta_dict),
@@ -805,11 +829,22 @@ impl PythonCodegen {
805
829
  )
806
830
  }
807
831
  } else if let Some(ref def) = field.default_value {
808
- let py_val = self.format_default_value(def, &field.type_ref);
809
- (
810
- base_type.to_string(),
811
- format!("field(default={}, metadata={})", py_val, meta_dict),
812
- )
832
+ if let Some((text_name, text_type)) = simple_content {
833
+ let py_val = self.format_default_value(def, &text_type, ir);
834
+ (
835
+ base_type.to_string(),
836
+ format!(
837
+ "field(default_factory=lambda: {}({}={}), metadata={})",
838
+ base_type, text_name, py_val, meta_dict
839
+ ),
840
+ )
841
+ } else {
842
+ let py_val = self.format_default_value(def, &field.type_ref, ir);
843
+ (
844
+ base_type.to_string(),
845
+ format!("field(default={}, metadata={})", py_val, meta_dict),
846
+ )
847
+ }
813
848
  } else {
814
849
  (
815
850
  base_type.to_string(),
@@ -825,6 +860,7 @@ impl PythonCodegen {
825
860
  is_list: bool,
826
861
  base_type: &str,
827
862
  meta_dict: &str,
863
+ ir: &SchemaIR,
828
864
  ) -> (String, String) {
829
865
  let facet_args = field
830
866
  .facets
@@ -843,6 +879,25 @@ impl PythonCodegen {
843
879
  }
844
880
  let extra_clause = clauses.join(", ");
845
881
 
882
+ let simple_content = match &field.type_ref {
883
+ TypeRef::Named(qname) => match ir.find_type(qname) {
884
+ Some(TypeDef::Struct(s)) => s
885
+ .fields
886
+ .iter()
887
+ .find(|f| f.kind == FieldKind::Text)
888
+ .map(|tf| (tf.name.clone(), tf.type_ref.clone())),
889
+ _ => None,
890
+ },
891
+ _ => None,
892
+ };
893
+
894
+ if field.kind == FieldKind::AnyAttribute {
895
+ return (
896
+ "dict[str, str]".to_string(),
897
+ format!("Field(default_factory=dict, {})", extra_clause),
898
+ );
899
+ }
900
+
846
901
  if is_list {
847
902
  (
848
903
  format!("list[{}]", base_type),
@@ -850,7 +905,7 @@ impl PythonCodegen {
850
905
  )
851
906
  } else if field.cardinality.is_optional() || field.nillable {
852
907
  if let Some(ref def) = field.default_value {
853
- let py_val = self.format_default_value(def, &field.type_ref);
908
+ let py_val = self.format_default_value(def, &field.type_ref, ir);
854
909
  (
855
910
  format!("{} | None", base_type),
856
911
  format!("Field(default={}, {})", py_val, extra_clause),
@@ -862,11 +917,22 @@ impl PythonCodegen {
862
917
  )
863
918
  }
864
919
  } else if let Some(ref def) = field.default_value {
865
- let py_val = self.format_default_value(def, &field.type_ref);
866
- (
867
- base_type.to_string(),
868
- format!("Field(default={}, {})", py_val, extra_clause),
869
- )
920
+ if let Some((text_name, text_type)) = simple_content {
921
+ let py_val = self.format_default_value(def, &text_type, ir);
922
+ (
923
+ base_type.to_string(),
924
+ format!(
925
+ "Field(default_factory=lambda: {}({}={}), {})",
926
+ base_type, text_name, py_val, extra_clause
927
+ ),
928
+ )
929
+ } else {
930
+ let py_val = self.format_default_value(def, &field.type_ref, ir);
931
+ (
932
+ base_type.to_string(),
933
+ format!("Field(default={}, {})", py_val, extra_clause),
934
+ )
935
+ }
870
936
  } else {
871
937
  (
872
938
  base_type.to_string(),
@@ -880,7 +946,8 @@ impl PythonCodegen {
880
946
  FieldKind::Element => "Element",
881
947
  FieldKind::Attribute => "Attribute",
882
948
  FieldKind::Text => "Text",
883
- FieldKind::Any | FieldKind::AnyAttribute => "Wildcard",
949
+ FieldKind::Any => "Wildcard",
950
+ FieldKind::AnyAttribute => "Attributes",
884
951
  };
885
952
 
886
953
  let mut parts = Vec::new();
@@ -901,8 +968,9 @@ impl PythonCodegen {
901
968
  format!("{{{}}}", parts.join(", "))
902
969
  }
903
970
 
904
- fn format_default_value(&self, val: &str, type_ref: &TypeRef) -> String {
905
- match type_ref {
971
+ fn format_default_value(&self, val: &str, type_ref: &TypeRef, ir: &SchemaIR) -> String {
972
+ let base = super::primitive_base(type_ref, ir);
973
+ match base {
906
974
  TypeRef::Primitive(PrimitiveType::Boolean) => match val.trim() {
907
975
  "true" | "1" => "True".to_string(),
908
976
  "false" | "0" => "False".to_string(),