polyxml 0.12.0__tar.gz → 0.14.0__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.12.0 → polyxml-0.14.0}/Cargo.lock +6 -5
- {polyxml-0.12.0 → polyxml-0.14.0}/Cargo.toml +1 -1
- {polyxml-0.12.0 → polyxml-0.14.0}/PKG-INFO +1 -1
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/Cargo.toml +1 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/csharp/mod.rs +63 -29
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/go/mod.rs +62 -26
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/python/mod.rs +34 -7
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/rust/mod.rs +61 -4
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/error.rs +3 -0
- polyxml-0.14.0/crates/polyxml-core/src/json.rs +356 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/lib.rs +4 -0
- polyxml-0.14.0/crates/polyxml-core/src/schema.rs +358 -0
- polyxml-0.14.0/crates/polyxml-core/src/transcoder.rs +377 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/value.rs +23 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_csharp_codegen.rs +39 -9
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_go_codegen.rs +45 -16
- polyxml-0.14.0/crates/polyxml-core/tests/test_json.rs +223 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_python_codegen.rs +15 -6
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_rust_codegen.rs +13 -0
- polyxml-0.14.0/crates/polyxml-core/tests/test_transcoder.rs +153 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-python/src/lib.rs +145 -0
- polyxml-0.14.0/crates/polyxml-python/tests/test_json.py +387 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/pyproject.toml +1 -1
- {polyxml-0.12.0 → polyxml-0.14.0}/python/polyxml/__init__.py +242 -1
- polyxml-0.14.0/python/polyxml/compat/__init__.py +1 -0
- polyxml-0.14.0/python/polyxml/compat/xsdata.py +36 -0
- polyxml-0.12.0/crates/polyxml-core/src/schema.rs +0 -167
- {polyxml-0.12.0 → polyxml-0.14.0}/README.md +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/mod.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/parser.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/schema_parser/mod.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/src/serializer.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.12.0 → polyxml-0.14.0}/python/polyxml/py.typed +0 -0
|
@@ -549,7 +549,7 @@ dependencies = [
|
|
|
549
549
|
|
|
550
550
|
[[package]]
|
|
551
551
|
name = "polyxml"
|
|
552
|
-
version = "0.
|
|
552
|
+
version = "0.14.0"
|
|
553
553
|
dependencies = [
|
|
554
554
|
"criterion",
|
|
555
555
|
"heck",
|
|
@@ -559,6 +559,7 @@ dependencies = [
|
|
|
559
559
|
"pretty_assertions",
|
|
560
560
|
"quick-xml",
|
|
561
561
|
"serde",
|
|
562
|
+
"serde_json",
|
|
562
563
|
"smallvec",
|
|
563
564
|
"tempfile",
|
|
564
565
|
"thiserror",
|
|
@@ -566,14 +567,14 @@ dependencies = [
|
|
|
566
567
|
|
|
567
568
|
[[package]]
|
|
568
569
|
name = "polyxml-c"
|
|
569
|
-
version = "0.
|
|
570
|
+
version = "0.14.0"
|
|
570
571
|
dependencies = [
|
|
571
572
|
"polyxml",
|
|
572
573
|
]
|
|
573
574
|
|
|
574
575
|
[[package]]
|
|
575
576
|
name = "polyxml-cli"
|
|
576
|
-
version = "0.
|
|
577
|
+
version = "0.14.0"
|
|
577
578
|
dependencies = [
|
|
578
579
|
"clap",
|
|
579
580
|
"glob",
|
|
@@ -587,7 +588,7 @@ dependencies = [
|
|
|
587
588
|
|
|
588
589
|
[[package]]
|
|
589
590
|
name = "polyxml-js"
|
|
590
|
-
version = "0.
|
|
591
|
+
version = "0.14.0"
|
|
591
592
|
dependencies = [
|
|
592
593
|
"napi",
|
|
593
594
|
"napi-build",
|
|
@@ -597,7 +598,7 @@ dependencies = [
|
|
|
597
598
|
|
|
598
599
|
[[package]]
|
|
599
600
|
name = "polyxml-python"
|
|
600
|
-
version = "0.
|
|
601
|
+
version = "0.14.0"
|
|
601
602
|
dependencies = [
|
|
602
603
|
"lexical-core",
|
|
603
604
|
"polyxml",
|
|
@@ -31,6 +31,8 @@ pub struct CSharpOptions {
|
|
|
31
31
|
pub namespace: String,
|
|
32
32
|
/// Emit System.Xml.Serialization attributes ([XmlElement], [XmlAttribute], etc.)
|
|
33
33
|
pub emit_xml_attributes: bool,
|
|
34
|
+
/// Emit System.Text.Json.Serialization attributes ([JsonPropertyName], etc.)
|
|
35
|
+
pub emit_json_attributes: bool,
|
|
34
36
|
/// Emit IValidatableObject and restriction facet validation logic
|
|
35
37
|
pub emit_validation: bool,
|
|
36
38
|
/// Record emission kind (record class vs record struct)
|
|
@@ -46,6 +48,7 @@ impl Default for CSharpOptions {
|
|
|
46
48
|
Self {
|
|
47
49
|
namespace: "Generated".to_string(),
|
|
48
50
|
emit_xml_attributes: true,
|
|
51
|
+
emit_json_attributes: true,
|
|
49
52
|
emit_validation: true,
|
|
50
53
|
record_kind: CSharpRecordKind::Class,
|
|
51
54
|
use_file_scoped_namespaces: true,
|
|
@@ -225,6 +228,9 @@ impl CSharpCodegen {
|
|
|
225
228
|
if self.options.emit_xml_attributes {
|
|
226
229
|
writeln!(out, "using System.Xml.Serialization;").unwrap();
|
|
227
230
|
}
|
|
231
|
+
if self.options.emit_json_attributes {
|
|
232
|
+
writeln!(out, "using System.Text.Json.Serialization;").unwrap();
|
|
233
|
+
}
|
|
228
234
|
writeln!(out).unwrap();
|
|
229
235
|
|
|
230
236
|
let ns = to_csharp_namespace(&self.options.namespace);
|
|
@@ -288,6 +294,14 @@ impl CSharpCodegen {
|
|
|
288
294
|
self.emit_docstring(out, doc, indent);
|
|
289
295
|
}
|
|
290
296
|
|
|
297
|
+
if self.options.emit_json_attributes {
|
|
298
|
+
writeln!(
|
|
299
|
+
out,
|
|
300
|
+
"{}[JsonConverter(typeof(JsonStringEnumConverter))]",
|
|
301
|
+
indent
|
|
302
|
+
)
|
|
303
|
+
.unwrap();
|
|
304
|
+
}
|
|
291
305
|
writeln!(out, "{}public enum {}", indent, enum_name).unwrap();
|
|
292
306
|
writeln!(out, "{}{{", indent).unwrap();
|
|
293
307
|
|
|
@@ -425,10 +439,17 @@ impl CSharpCodegen {
|
|
|
425
439
|
self.emit_docstring(out, doc, &format!("{} ", indent));
|
|
426
440
|
}
|
|
427
441
|
|
|
428
|
-
let
|
|
429
|
-
|
|
430
|
-
|
|
442
|
+
let mut branch_attrs = Vec::new();
|
|
443
|
+
if self.options.emit_xml_attributes {
|
|
444
|
+
branch_attrs.push(format!("XmlElement(\"{}\")", branch.xml_name));
|
|
445
|
+
}
|
|
446
|
+
if self.options.emit_json_attributes {
|
|
447
|
+
branch_attrs.push(format!("JsonPropertyName(\"{}\")", branch.xml_name));
|
|
448
|
+
}
|
|
449
|
+
let xml_attr = if branch_attrs.is_empty() {
|
|
431
450
|
String::new()
|
|
451
|
+
} else {
|
|
452
|
+
format!("[property: {}] ", branch_attrs.join(", "))
|
|
432
453
|
};
|
|
433
454
|
|
|
434
455
|
writeln!(
|
|
@@ -529,11 +550,7 @@ impl CSharpCodegen {
|
|
|
529
550
|
|
|
530
551
|
let default_val = if can_have_default { " = null" } else { "" };
|
|
531
552
|
|
|
532
|
-
let
|
|
533
|
-
self.build_field_xml_attribute(f, ir)
|
|
534
|
-
} else {
|
|
535
|
-
String::new()
|
|
536
|
-
};
|
|
553
|
+
let field_attrs = self.build_field_attributes(f, ir);
|
|
537
554
|
|
|
538
555
|
if let Some(ref doc) = f.documentation {
|
|
539
556
|
self.emit_docstring(out, doc, &format!("{} ", indent));
|
|
@@ -542,7 +559,7 @@ impl CSharpCodegen {
|
|
|
542
559
|
writeln!(
|
|
543
560
|
out,
|
|
544
561
|
"{} {}{} {}{}{}",
|
|
545
|
-
indent,
|
|
562
|
+
indent, field_attrs, field_type, prop_name, default_val, comma
|
|
546
563
|
)
|
|
547
564
|
.unwrap();
|
|
548
565
|
}
|
|
@@ -709,31 +726,48 @@ impl CSharpCodegen {
|
|
|
709
726
|
}
|
|
710
727
|
}
|
|
711
728
|
|
|
712
|
-
fn
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
let
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
729
|
+
fn build_field_attributes(&self, f: &FieldDef, ir: &SchemaIR) -> String {
|
|
730
|
+
let mut parts = Vec::new();
|
|
731
|
+
|
|
732
|
+
if self.options.emit_xml_attributes {
|
|
733
|
+
// If the field is a choice (UnionDef), emit XmlElement("branchXml", typeof(BranchType))
|
|
734
|
+
if let TypeRef::Named(ref qname) = f.type_ref {
|
|
735
|
+
if let Some(TypeDef::Union(u)) = ir.types.get(qname) {
|
|
736
|
+
let choice_name = to_csharp_type_name(&u.qname.local);
|
|
737
|
+
for branch in &u.branches {
|
|
738
|
+
let variant_name = to_csharp_type_name(&branch.variant_name);
|
|
739
|
+
parts.push(format!(
|
|
740
|
+
"XmlElement(\"{}\", typeof({}.{}))",
|
|
741
|
+
branch.xml_name, choice_name, variant_name
|
|
742
|
+
));
|
|
743
|
+
}
|
|
724
744
|
}
|
|
725
|
-
|
|
726
|
-
|
|
745
|
+
}
|
|
746
|
+
if parts.is_empty() {
|
|
747
|
+
match f.kind {
|
|
748
|
+
FieldKind::Attribute => parts.push(format!("XmlAttribute(\"{}\")", f.xml_name)),
|
|
749
|
+
FieldKind::Text => parts.push("XmlText".to_string()),
|
|
750
|
+
FieldKind::Any => parts.push("XmlAnyElement".to_string()),
|
|
751
|
+
FieldKind::AnyAttribute => parts.push("XmlAnyAttribute".to_string()),
|
|
752
|
+
FieldKind::Element => parts.push(format!("XmlElement(\"{}\")", f.xml_name)),
|
|
727
753
|
}
|
|
728
754
|
}
|
|
729
755
|
}
|
|
730
756
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
FieldKind::
|
|
757
|
+
if self.options.emit_json_attributes {
|
|
758
|
+
let json_name = match f.kind {
|
|
759
|
+
FieldKind::Text => "value",
|
|
760
|
+
_ => &f.xml_name,
|
|
761
|
+
};
|
|
762
|
+
if f.kind != FieldKind::Any && f.kind != FieldKind::AnyAttribute {
|
|
763
|
+
parts.push(format!("JsonPropertyName(\"{}\")", json_name));
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
if parts.is_empty() {
|
|
768
|
+
String::new()
|
|
769
|
+
} else {
|
|
770
|
+
format!("[property: {}] ", parts.join(", "))
|
|
737
771
|
}
|
|
738
772
|
}
|
|
739
773
|
|
|
@@ -16,6 +16,8 @@ pub struct GoOptions {
|
|
|
16
16
|
pub package_name: String,
|
|
17
17
|
/// Emit encoding/xml tags (default: true)
|
|
18
18
|
pub emit_xml_tags: bool,
|
|
19
|
+
/// Emit encoding/json tags (default: true)
|
|
20
|
+
pub emit_json_tags: bool,
|
|
19
21
|
/// Emit custom UnmarshalXML/MarshalXML for xs:choice mutual exclusivity validation (default: true)
|
|
20
22
|
pub validate_choice_exclusivity: bool,
|
|
21
23
|
/// Emit Validate() error method for restriction facets (default: true)
|
|
@@ -29,6 +31,7 @@ impl Default for GoOptions {
|
|
|
29
31
|
Self {
|
|
30
32
|
package_name: "models".to_string(),
|
|
31
33
|
emit_xml_tags: true,
|
|
34
|
+
emit_json_tags: true,
|
|
32
35
|
validate_choice_exclusivity: true,
|
|
33
36
|
validate_facets: true,
|
|
34
37
|
emit_root_aliases: true,
|
|
@@ -540,7 +543,11 @@ impl GoCodegen {
|
|
|
540
543
|
|
|
541
544
|
// Emit XMLName if xml tags enabled
|
|
542
545
|
if self.options.emit_xml_tags {
|
|
543
|
-
|
|
546
|
+
if self.options.emit_json_tags {
|
|
547
|
+
writeln!(out, " XMLName xml.Name `json:\"-\"`").unwrap();
|
|
548
|
+
} else {
|
|
549
|
+
writeln!(out, " XMLName xml.Name").unwrap();
|
|
550
|
+
}
|
|
544
551
|
}
|
|
545
552
|
|
|
546
553
|
// Struct composition / inheritance if base struct exists
|
|
@@ -562,10 +569,17 @@ impl GoCodegen {
|
|
|
562
569
|
.iter()
|
|
563
570
|
.any(|f| f.name == "value" || f.kind == FieldKind::Text);
|
|
564
571
|
if !has_value_field {
|
|
565
|
-
let
|
|
566
|
-
|
|
572
|
+
let mut parts = Vec::new();
|
|
573
|
+
if self.options.emit_xml_tags {
|
|
574
|
+
parts.push("xml:\",chardata\"".to_string());
|
|
575
|
+
}
|
|
576
|
+
if self.options.emit_json_tags {
|
|
577
|
+
parts.push("json:\"value,omitempty\"".to_string());
|
|
578
|
+
}
|
|
579
|
+
let tag = if parts.is_empty() {
|
|
580
|
+
String::new()
|
|
567
581
|
} else {
|
|
568
|
-
""
|
|
582
|
+
format!(" `{}`", parts.join(" "))
|
|
569
583
|
};
|
|
570
584
|
writeln!(out, " Value {}{}", base_type_str, tag).unwrap();
|
|
571
585
|
}
|
|
@@ -579,7 +593,7 @@ impl GoCodegen {
|
|
|
579
593
|
|
|
580
594
|
let field_name = to_go_field_name(&f.name);
|
|
581
595
|
let field_type = self.resolve_field_type(f);
|
|
582
|
-
let tag = self.
|
|
596
|
+
let tag = self.build_field_struct_tags(f);
|
|
583
597
|
writeln!(out, " {} {}{}", field_name, field_type, tag).unwrap();
|
|
584
598
|
}
|
|
585
599
|
|
|
@@ -606,30 +620,52 @@ impl GoCodegen {
|
|
|
606
620
|
}
|
|
607
621
|
}
|
|
608
622
|
|
|
609
|
-
fn
|
|
610
|
-
|
|
611
|
-
return String::new();
|
|
612
|
-
}
|
|
623
|
+
fn build_field_struct_tags(&self, f: &FieldDef) -> String {
|
|
624
|
+
let mut parts = Vec::new();
|
|
613
625
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
626
|
+
if self.options.emit_xml_tags {
|
|
627
|
+
let is_opt = f.cardinality.is_optional() || f.nillable;
|
|
628
|
+
let xml_val = match f.kind {
|
|
629
|
+
FieldKind::Attribute => {
|
|
630
|
+
if is_opt {
|
|
631
|
+
format!("{},attr,omitempty", f.xml_name)
|
|
632
|
+
} else {
|
|
633
|
+
format!("{},attr", f.xml_name)
|
|
634
|
+
}
|
|
621
635
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
636
|
+
FieldKind::Text => ",chardata".to_string(),
|
|
637
|
+
FieldKind::Any => ",any".to_string(),
|
|
638
|
+
FieldKind::AnyAttribute => ",any,attr".to_string(),
|
|
639
|
+
FieldKind::Element => {
|
|
640
|
+
if is_opt {
|
|
641
|
+
format!("{},omitempty", f.xml_name)
|
|
642
|
+
} else {
|
|
643
|
+
f.xml_name.clone()
|
|
644
|
+
}
|
|
631
645
|
}
|
|
632
|
-
}
|
|
646
|
+
};
|
|
647
|
+
parts.push(format!("xml:\"{}\"", xml_val));
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if self.options.emit_json_tags {
|
|
651
|
+
let is_opt = f.cardinality.is_optional() || f.nillable;
|
|
652
|
+
let json_name = if f.kind == FieldKind::Text {
|
|
653
|
+
"value".to_string()
|
|
654
|
+
} else {
|
|
655
|
+
f.xml_name.clone()
|
|
656
|
+
};
|
|
657
|
+
let json_val = if is_opt {
|
|
658
|
+
format!("{},omitempty", json_name)
|
|
659
|
+
} else {
|
|
660
|
+
json_name
|
|
661
|
+
};
|
|
662
|
+
parts.push(format!("json:\"{}\"", json_val));
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if parts.is_empty() {
|
|
666
|
+
String::new()
|
|
667
|
+
} else {
|
|
668
|
+
format!(" `{}`", parts.join(" "))
|
|
633
669
|
}
|
|
634
670
|
}
|
|
635
671
|
|
|
@@ -38,6 +38,7 @@ pub struct PythonOptions {
|
|
|
38
38
|
pub emit_meta: bool,
|
|
39
39
|
pub emit_root_aliases: bool,
|
|
40
40
|
pub emit_codecs: bool,
|
|
41
|
+
pub emit_json_metadata: bool,
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
impl Default for PythonOptions {
|
|
@@ -50,6 +51,7 @@ impl Default for PythonOptions {
|
|
|
50
51
|
emit_meta: true,
|
|
51
52
|
emit_root_aliases: true,
|
|
52
53
|
emit_codecs: true,
|
|
54
|
+
emit_json_metadata: true,
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
}
|
|
@@ -529,7 +531,23 @@ impl PythonCodegen {
|
|
|
529
531
|
out.push_str(" ) -> bytes:\n");
|
|
530
532
|
out.push_str(" \"\"\"Serialize this model instance into XML bytes.\"\"\"\n");
|
|
531
533
|
out.push_str(" import polyxml\n");
|
|
532
|
-
out.push_str(" return polyxml.serialize(self, indent=indent, namespaces=namespaces, ns_map=ns_map)\n");
|
|
534
|
+
out.push_str(" return polyxml.serialize(self, indent=indent, namespaces=namespaces, ns_map=ns_map)\n\n");
|
|
535
|
+
out.push_str(" @classmethod\n");
|
|
536
|
+
out.push_str(" def from_json(cls, data: bytes | str) -> Self:\n");
|
|
537
|
+
out.push_str(" \"\"\"Deserialize JSON bytes or string into this model.\"\"\"\n");
|
|
538
|
+
out.push_str(" import polyxml\n");
|
|
539
|
+
out.push_str(" return polyxml.deserialize_json(data, cls)\n\n");
|
|
540
|
+
out.push_str(" def to_json(\n");
|
|
541
|
+
out.push_str(" self,\n");
|
|
542
|
+
out.push_str(" *,\n");
|
|
543
|
+
out.push_str(" indent: int | None = None,\n");
|
|
544
|
+
out.push_str(" by_alias: bool = True,\n");
|
|
545
|
+
out.push_str(" ) -> bytes:\n");
|
|
546
|
+
out.push_str(" \"\"\"Serialize this model instance into JSON bytes.\"\"\"\n");
|
|
547
|
+
out.push_str(" import polyxml\n");
|
|
548
|
+
out.push_str(
|
|
549
|
+
" return polyxml.serialize_json(self, indent=indent, by_alias=by_alias)\n",
|
|
550
|
+
);
|
|
533
551
|
has_body = true;
|
|
534
552
|
}
|
|
535
553
|
|
|
@@ -563,7 +581,7 @@ impl PythonCodegen {
|
|
|
563
581
|
self.format_dataclass_field(field, is_list, &inner_type, &meta_dict)
|
|
564
582
|
}
|
|
565
583
|
PythonBackend::Pydantic => {
|
|
566
|
-
self.format_pydantic_field(field, is_list, &inner_type, &meta_dict)
|
|
584
|
+
self.format_pydantic_field(field, py_name, is_list, &inner_type, &meta_dict)
|
|
567
585
|
}
|
|
568
586
|
};
|
|
569
587
|
|
|
@@ -616,6 +634,7 @@ impl PythonCodegen {
|
|
|
616
634
|
fn format_pydantic_field(
|
|
617
635
|
&self,
|
|
618
636
|
field: &FieldDef,
|
|
637
|
+
py_name: &str,
|
|
619
638
|
is_list: bool,
|
|
620
639
|
base_type: &str,
|
|
621
640
|
meta_dict: &str,
|
|
@@ -626,11 +645,16 @@ impl PythonCodegen {
|
|
|
626
645
|
.map(|f| self.format_pydantic_facets(f))
|
|
627
646
|
.unwrap_or_default();
|
|
628
647
|
|
|
629
|
-
let
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
format!("
|
|
633
|
-
}
|
|
648
|
+
let mut clauses = Vec::new();
|
|
649
|
+
if self.options.emit_json_metadata && py_name != field.xml_name {
|
|
650
|
+
clauses.push(format!("alias=\"{}\"", field.xml_name));
|
|
651
|
+
clauses.push(format!("serialization_alias=\"{}\"", field.xml_name));
|
|
652
|
+
}
|
|
653
|
+
clauses.push(format!("json_schema_extra={}", meta_dict));
|
|
654
|
+
if !facet_args.is_empty() {
|
|
655
|
+
clauses.push(facet_args);
|
|
656
|
+
}
|
|
657
|
+
let extra_clause = clauses.join(", ");
|
|
634
658
|
|
|
635
659
|
if is_list {
|
|
636
660
|
(
|
|
@@ -675,6 +699,9 @@ impl PythonCodegen {
|
|
|
675
699
|
let mut parts = Vec::new();
|
|
676
700
|
parts.push(format!("\"type\": \"{}\"", kind_str));
|
|
677
701
|
parts.push(format!("\"name\": \"{}\"", field.xml_name));
|
|
702
|
+
if self.options.emit_json_metadata {
|
|
703
|
+
parts.push(format!("\"json_name\": \"{}\"", field.xml_name));
|
|
704
|
+
}
|
|
678
705
|
|
|
679
706
|
if let Some(ref ns) = field.namespace {
|
|
680
707
|
parts.push(format!("\"namespace\": \"{}\"", ns));
|
|
@@ -1240,6 +1240,36 @@ impl RustCodegen {
|
|
|
1240
1240
|
out.push_str(" String::from_utf8(bytes).map_err(|e| PolyXmlError::Utf8Error(e.utf8_error()))\n");
|
|
1241
1241
|
out.push_str(" }\n\n");
|
|
1242
1242
|
|
|
1243
|
+
if self.options.derive_serde {
|
|
1244
|
+
let from_json_sig = if needs_lifetime {
|
|
1245
|
+
"pub fn from_json_str(json_str: &'a str) -> std::result::Result<Self, serde_json::Error>"
|
|
1246
|
+
} else {
|
|
1247
|
+
"pub fn from_json_str(json_str: &str) -> std::result::Result<Self, serde_json::Error>"
|
|
1248
|
+
};
|
|
1249
|
+
let _ = writeln!(out, " {}", from_json_sig);
|
|
1250
|
+
out.push_str(" {\n");
|
|
1251
|
+
out.push_str(" serde_json::from_str(json_str)\n");
|
|
1252
|
+
out.push_str(" }\n\n");
|
|
1253
|
+
|
|
1254
|
+
let from_json_slice_sig = if needs_lifetime {
|
|
1255
|
+
"pub fn from_json_slice(bytes: &'a [u8]) -> std::result::Result<Self, serde_json::Error>"
|
|
1256
|
+
} else {
|
|
1257
|
+
"pub fn from_json_slice(bytes: &[u8]) -> std::result::Result<Self, serde_json::Error>"
|
|
1258
|
+
};
|
|
1259
|
+
let _ = writeln!(out, " {}", from_json_slice_sig);
|
|
1260
|
+
out.push_str(" {\n");
|
|
1261
|
+
out.push_str(" serde_json::from_slice(bytes)\n");
|
|
1262
|
+
out.push_str(" }\n\n");
|
|
1263
|
+
|
|
1264
|
+
out.push_str(" pub fn to_json_string(&self) -> std::result::Result<String, serde_json::Error> {\n");
|
|
1265
|
+
out.push_str(" serde_json::to_string(self)\n");
|
|
1266
|
+
out.push_str(" }\n\n");
|
|
1267
|
+
|
|
1268
|
+
out.push_str(" pub fn to_json_vec(&self) -> std::result::Result<Vec<u8>, serde_json::Error> {\n");
|
|
1269
|
+
out.push_str(" serde_json::to_vec(self)\n");
|
|
1270
|
+
out.push_str(" }\n\n");
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1243
1273
|
out.push_str(" pub fn encode_xml<W: std::io::Write>(&self, writer: &mut Writer<W>, tag_name: Option<&str>) -> Result<()> {\n");
|
|
1244
1274
|
let _ = writeln!(
|
|
1245
1275
|
out,
|
|
@@ -1860,13 +1890,40 @@ impl RustCodegen {
|
|
|
1860
1890
|
out.push_str(" }\n\n");
|
|
1861
1891
|
|
|
1862
1892
|
out.push_str(" pub fn to_xml_string(&self) -> Result<String> {\n");
|
|
1863
|
-
out.push_str(
|
|
1864
|
-
" let bytes = self.to_xml()?;
|
|
1865
|
-
",
|
|
1866
|
-
);
|
|
1893
|
+
out.push_str(" let bytes = self.to_xml()?;\n");
|
|
1867
1894
|
out.push_str(" String::from_utf8(bytes).map_err(|e| PolyXmlError::Utf8Error(e.utf8_error()))\n");
|
|
1868
1895
|
out.push_str(" }\n\n");
|
|
1869
1896
|
|
|
1897
|
+
if self.options.derive_serde {
|
|
1898
|
+
let from_json_sig = if needs_lifetime {
|
|
1899
|
+
"pub fn from_json_str(json_str: &'a str) -> std::result::Result<Self, serde_json::Error>"
|
|
1900
|
+
} else {
|
|
1901
|
+
"pub fn from_json_str(json_str: &str) -> std::result::Result<Self, serde_json::Error>"
|
|
1902
|
+
};
|
|
1903
|
+
let _ = writeln!(out, " {}", from_json_sig);
|
|
1904
|
+
out.push_str(" {\n");
|
|
1905
|
+
out.push_str(" serde_json::from_str(json_str)\n");
|
|
1906
|
+
out.push_str(" }\n\n");
|
|
1907
|
+
|
|
1908
|
+
let from_json_slice_sig = if needs_lifetime {
|
|
1909
|
+
"pub fn from_json_slice(bytes: &'a [u8]) -> std::result::Result<Self, serde_json::Error>"
|
|
1910
|
+
} else {
|
|
1911
|
+
"pub fn from_json_slice(bytes: &[u8]) -> std::result::Result<Self, serde_json::Error>"
|
|
1912
|
+
};
|
|
1913
|
+
let _ = writeln!(out, " {}", from_json_slice_sig);
|
|
1914
|
+
out.push_str(" {\n");
|
|
1915
|
+
out.push_str(" serde_json::from_slice(bytes)\n");
|
|
1916
|
+
out.push_str(" }\n\n");
|
|
1917
|
+
|
|
1918
|
+
out.push_str(" pub fn to_json_string(&self) -> std::result::Result<String, serde_json::Error> {\n");
|
|
1919
|
+
out.push_str(" serde_json::to_string(self)\n");
|
|
1920
|
+
out.push_str(" }\n\n");
|
|
1921
|
+
|
|
1922
|
+
out.push_str(" pub fn to_json_vec(&self) -> std::result::Result<Vec<u8>, serde_json::Error> {\n");
|
|
1923
|
+
out.push_str(" serde_json::to_vec(self)\n");
|
|
1924
|
+
out.push_str(" }\n\n");
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1870
1927
|
out.push_str(" pub fn encode_xml<W: std::io::Write>(&self, writer: &mut Writer<W>, tag_name: Option<&str>) -> Result<()> {\n");
|
|
1871
1928
|
out.push_str(" match self {\n");
|
|
1872
1929
|
for branch in &u.branches {
|