polyxml 0.33.3__tar.gz → 0.33.4__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.3 → polyxml-0.33.4}/Cargo.lock +6 -6
  2. {polyxml-0.33.3 → polyxml-0.33.4}/Cargo.toml +1 -1
  3. {polyxml-0.33.3 → polyxml-0.33.4}/PKG-INFO +1 -1
  4. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/go/mod.rs +43 -8
  5. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/schema_parser/mod.rs +41 -16
  6. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_go_codegen.rs +112 -0
  7. {polyxml-0.33.3 → polyxml-0.33.4}/pyproject.toml +1 -1
  8. {polyxml-0.33.3 → polyxml-0.33.4}/README.md +0 -0
  9. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/Cargo.toml +0 -0
  10. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/README.md +0 -0
  11. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
  12. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
  13. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
  14. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
  15. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
  16. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
  17. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
  18. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
  19. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/mod.rs +0 -0
  20. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
  21. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
  22. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
  23. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
  24. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/converters.rs +0 -0
  25. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/error.rs +0 -0
  26. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/ir/chunker.rs +0 -0
  27. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/ir/mod.rs +0 -0
  28. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
  29. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/json.rs +0 -0
  30. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/lib.rs +0 -0
  31. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/parser.rs +0 -0
  32. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/schema.rs +0 -0
  33. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/serializer.rs +0 -0
  34. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/transcoder.rs +0 -0
  35. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/src/value.rs +0 -0
  36. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
  37. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
  38. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
  39. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
  40. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_any_attribute.rs +0 -0
  41. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_any_element.rs +0 -0
  42. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_conformance.rs +0 -0
  43. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_core.rs +0 -0
  44. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
  45. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
  46. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
  47. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_json.rs +0 -0
  48. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
  49. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
  50. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
  51. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
  52. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
  53. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
  54. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
  55. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
  56. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_security.rs +0 -0
  57. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
  58. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
  59. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
  60. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
  61. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/Cargo.toml +0 -0
  62. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/README.md +0 -0
  63. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
  64. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/src/lib.rs +0 -0
  65. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/tests/test_conformance.py +0 -0
  66. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/tests/test_generated_models.py +0 -0
  67. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/tests/test_json.py +0 -0
  68. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
  69. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/tests/test_polyxml.py +0 -0
  70. {polyxml-0.33.3 → polyxml-0.33.4}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
  71. {polyxml-0.33.3 → polyxml-0.33.4}/python/polyxml/AGENT_GUIDE.md +0 -0
  72. {polyxml-0.33.3 → polyxml-0.33.4}/python/polyxml/__init__.py +0 -0
  73. {polyxml-0.33.3 → polyxml-0.33.4}/python/polyxml/compat/__init__.py +0 -0
  74. {polyxml-0.33.3 → polyxml-0.33.4}/python/polyxml/compat/xsdata.py +0 -0
  75. {polyxml-0.33.3 → polyxml-0.33.4}/python/polyxml/py.typed +0 -0
@@ -608,7 +608,7 @@ dependencies = [
608
608
 
609
609
  [[package]]
610
610
  name = "polyxml"
611
- version = "0.33.3"
611
+ version = "0.33.4"
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.3"
632
+ version = "0.33.4"
633
633
  dependencies = [
634
634
  "polyxml",
635
635
  ]
636
636
 
637
637
  [[package]]
638
638
  name = "polyxml-cli"
639
- version = "0.33.3"
639
+ version = "0.33.4"
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.3"
653
+ version = "0.33.4"
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.3"
663
+ version = "0.33.4"
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.3"
673
+ version = "0.33.4"
674
674
  dependencies = [
675
675
  "polyxml",
676
676
  "quick-xml",
@@ -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.3"
6
+ version = "0.33.4"
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.3
3
+ Version: 0.33.4
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -586,7 +586,11 @@ impl GoCodegen {
586
586
  let mapped_type = self.context.map_type_ref(&branch.type_ref);
587
587
  let mut tag_parts = Vec::new();
588
588
  if self.options.emit_xml_tags {
589
- tag_parts.push(format!("xml:\"{},omitempty\"", branch.xml_name));
589
+ let branch_xml = match &branch.namespace {
590
+ Some(ns) if !ns.is_empty() => format!("{} {}", ns, branch.xml_name),
591
+ _ => branch.xml_name.clone(),
592
+ };
593
+ tag_parts.push(format!("xml:\"{},omitempty\"", branch_xml));
590
594
  }
591
595
  if self.options.emit_json_tags {
592
596
  tag_parts.push(format!("json:\"{},omitempty\"", branch.xml_name));
@@ -1026,7 +1030,7 @@ impl GoCodegen {
1026
1030
  }
1027
1031
 
1028
1032
  let field_type = self.resolve_field_type(f);
1029
- let tag = self.build_field_struct_tags(f, &mut seen_json);
1033
+ let tag = self.build_field_struct_tags(f, s, ir, &mut seen_json);
1030
1034
  writeln!(out, " {} {}{}", field_name, field_type, tag).unwrap();
1031
1035
  }
1032
1036
 
@@ -1144,29 +1148,44 @@ impl GoCodegen {
1144
1148
  }
1145
1149
  }
1146
1150
 
1147
- fn build_field_struct_tags(&self, f: &FieldDef, seen_json: &mut HashSet<String>) -> String {
1151
+ fn build_field_struct_tags(
1152
+ &self,
1153
+ f: &FieldDef,
1154
+ s: &StructDef,
1155
+ ir: &SchemaIR,
1156
+ seen_json: &mut HashSet<String>,
1157
+ ) -> String {
1148
1158
  let mut parts = Vec::new();
1149
1159
 
1150
1160
  if self.options.emit_xml_tags {
1151
1161
  let is_opt = f.cardinality.is_optional() || f.nillable;
1152
1162
  let xml_val = match f.kind {
1153
1163
  FieldKind::Attribute => {
1164
+ let attr_name = match &f.namespace {
1165
+ Some(ns) if !ns.is_empty() => format!("{} {}", ns, f.xml_name),
1166
+ _ => f.xml_name.clone(),
1167
+ };
1154
1168
  if is_opt {
1155
- format!("{},attr,omitempty", f.xml_name)
1169
+ format!("{},attr,omitempty", attr_name)
1156
1170
  } else {
1157
- format!("{},attr", f.xml_name)
1171
+ format!("{},attr", attr_name)
1158
1172
  }
1159
1173
  }
1160
1174
  FieldKind::Text => ",chardata".to_string(),
1161
1175
  FieldKind::Any => ",any".to_string(),
1162
1176
  FieldKind::AnyAttribute => ",any,attr".to_string(),
1163
1177
  FieldKind::Element => {
1178
+ let elem_name = if is_namespaced_ref(f, s, ir) {
1179
+ format!("{} {}", f.namespace.as_ref().unwrap(), f.xml_name)
1180
+ } else {
1181
+ f.xml_name.clone()
1182
+ };
1164
1183
  if f.xml_name.is_empty() {
1165
1184
  ",any".to_string()
1166
1185
  } else if is_opt {
1167
- format!("{},omitempty", f.xml_name)
1186
+ format!("{},omitempty", elem_name)
1168
1187
  } else {
1169
- f.xml_name.clone()
1188
+ elem_name
1170
1189
  }
1171
1190
  }
1172
1191
  };
@@ -1311,7 +1330,7 @@ impl GoCodegen {
1311
1330
  let mut seen_json = HashSet::new();
1312
1331
  for (f, field_name) in s.fields.iter().zip(&field_names) {
1313
1332
  let field_type = self.resolve_field_type(f);
1314
- let tag = self.build_field_struct_tags(f, &mut seen_json);
1333
+ let tag = self.build_field_struct_tags(f, s, ir, &mut seen_json);
1315
1334
  writeln!(out, " {} {}{}", field_name, field_type, tag).unwrap();
1316
1335
  }
1317
1336
  writeln!(out, "}}\n").unwrap();
@@ -1647,3 +1666,19 @@ fn concrete_derivations<'a>(s: &'a StructDef, ir: &'a SchemaIR) -> Vec<&'a Struc
1647
1666
  result.sort_by(|a, b| a.qname.local.cmp(&b.qname.local));
1648
1667
  result
1649
1668
  }
1669
+
1670
+ fn is_namespaced_ref(f: &FieldDef, s: &StructDef, ir: &SchemaIR) -> bool {
1671
+ let Some(ref ns) = f.namespace else {
1672
+ return false;
1673
+ };
1674
+ if ns.is_empty() {
1675
+ return false;
1676
+ }
1677
+ // If field namespace is different from struct namespace, it's definitely an external ref
1678
+ if s.qname.namespace.as_deref() != Some(ns.as_str()) {
1679
+ return true;
1680
+ }
1681
+ // If it matches a global element definition, it's an element ref
1682
+ let q = QName::new(Some(ns.as_str()), &f.xml_name);
1683
+ ir.elements.contains_key(&q)
1684
+ }
@@ -1805,16 +1805,29 @@ fn parse_element_field(
1805
1805
  in_choice: bool,
1806
1806
  in_unbounded_compositor: bool,
1807
1807
  ) -> Option<FieldDef> {
1808
- let name = get_attr_value(e, "name")
1809
- .or_else(|| get_attr_value(e, "ref").map(|r| strip_prefix(&r).to_string()))?;
1810
-
1811
- let xml_name = get_attr_value(e, "name")
1812
- .or_else(|| get_attr_value(e, "ref"))
1813
- .unwrap_or_else(|| name.clone());
1808
+ let ref_attr = get_attr_value(e, "ref");
1809
+ let name_attr = get_attr_value(e, "name");
1810
+
1811
+ let (name, xml_name, namespace) = if let Some(ref r) = ref_attr {
1812
+ let qname = resolve_qname(r, target_ns, prefixes);
1813
+ let field_name = name_attr.unwrap_or_else(|| qname.local.clone());
1814
+ let xml_name = qname.local;
1815
+ let namespace = qname.namespace;
1816
+ (field_name, xml_name, namespace)
1817
+ } else {
1818
+ let n = name_attr?;
1819
+ let xml_name = n.clone();
1820
+ let namespace = target_ns.map(Into::into);
1821
+ (n, xml_name, namespace)
1822
+ };
1814
1823
 
1815
1824
  let type_ref = get_attr_value(e, "type")
1816
1825
  .map(|t| resolve_type_ref(&t, target_ns, prefixes))
1817
- .or_else(|| get_attr_value(e, "ref").map(|r| resolve_type_ref(&r, target_ns, prefixes)))
1826
+ .or_else(|| {
1827
+ ref_attr
1828
+ .as_ref()
1829
+ .map(|r| resolve_type_ref(r, target_ns, prefixes))
1830
+ })
1818
1831
  .unwrap_or(TypeRef::Primitive(PrimitiveType::String));
1819
1832
 
1820
1833
  let min_occurs = if in_choice {
@@ -1845,7 +1858,7 @@ fn parse_element_field(
1845
1858
  Some(FieldDef {
1846
1859
  name: sanitize_field_name(&name),
1847
1860
  xml_name,
1848
- namespace: target_ns.map(Into::into),
1861
+ namespace,
1849
1862
  kind: FieldKind::Element,
1850
1863
  type_ref,
1851
1864
  cardinality: Cardinality {
@@ -1866,16 +1879,28 @@ fn parse_attribute_field(
1866
1879
  target_ns: Option<&str>,
1867
1880
  prefixes: &HashMap<String, String>,
1868
1881
  ) -> Option<FieldDef> {
1869
- let name = get_attr_value(e, "name")
1870
- .or_else(|| get_attr_value(e, "ref").map(|r| strip_prefix(&r).to_string()))?;
1871
-
1872
- let xml_name = get_attr_value(e, "name")
1873
- .or_else(|| get_attr_value(e, "ref"))
1874
- .unwrap_or_else(|| name.clone());
1882
+ let ref_attr = get_attr_value(e, "ref");
1883
+ let name_attr = get_attr_value(e, "name");
1884
+
1885
+ let (name, xml_name, namespace) = if let Some(ref r) = ref_attr {
1886
+ let qname = resolve_qname(r, target_ns, prefixes);
1887
+ let field_name = name_attr.unwrap_or_else(|| qname.local.clone());
1888
+ let xml_name = qname.local;
1889
+ let namespace = qname.namespace;
1890
+ (field_name, xml_name, namespace)
1891
+ } else {
1892
+ let n = name_attr?;
1893
+ let xml_name = n.clone();
1894
+ (n, xml_name, None)
1895
+ };
1875
1896
 
1876
1897
  let type_ref = get_attr_value(e, "type")
1877
1898
  .map(|t| resolve_type_ref(&t, target_ns, prefixes))
1878
- .or_else(|| get_attr_value(e, "ref").map(|r| resolve_type_ref(&r, target_ns, prefixes)))
1899
+ .or_else(|| {
1900
+ ref_attr
1901
+ .as_ref()
1902
+ .map(|r| resolve_type_ref(r, target_ns, prefixes))
1903
+ })
1879
1904
  .unwrap_or(TypeRef::Primitive(PrimitiveType::String));
1880
1905
 
1881
1906
  let is_required = get_attr_value(e, "use")
@@ -1894,7 +1919,7 @@ fn parse_attribute_field(
1894
1919
  Some(FieldDef {
1895
1920
  name: sanitize_field_name(&name),
1896
1921
  xml_name,
1897
- namespace: None, // Attributes are unqualified by default unless form="qualified"
1922
+ namespace,
1898
1923
  kind: FieldKind::Attribute,
1899
1924
  type_ref,
1900
1925
  cardinality,
@@ -966,3 +966,115 @@ func TestAbstractDocumentRoundTrip(t *testing.T) {
966
966
  String::from_utf8_lossy(&output.stderr)
967
967
  );
968
968
  }
969
+
970
+ #[test]
971
+ fn test_go_namespaced_element_ref_matching() {
972
+ let schema = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
973
+ xmlns:t="urn:audit:ref" targetNamespace="urn:audit:ref"
974
+ elementFormDefault="qualified">
975
+ <xs:element name="Child" type="xs:string"/>
976
+ <xs:element name="Container"><xs:complexType><xs:sequence>
977
+ <xs:element ref="t:Child"/>
978
+ </xs:sequence></xs:complexType></xs:element>
979
+ </xs:schema>"#;
980
+
981
+ let ir = XsdParser::new().parse_str(schema).unwrap();
982
+ let codegen = GoCodegen::new(GoOptions::default());
983
+ let code = codegen.generate_module(&ir);
984
+
985
+ // Code must NOT contain schema prefix t:Child
986
+ assert!(
987
+ !code.contains("\"t:Child\""),
988
+ "Go codegen must not emit schema lexical prefix in tags: {code}"
989
+ );
990
+ // Code must emit expanded namespace QName
991
+ assert!(
992
+ code.contains("`xml:\"urn:audit:ref Child\" json:\"Child\"`"),
993
+ "Go codegen must emit expanded QName and clean JSON name in tags: {code}"
994
+ );
995
+
996
+ if Command::new("go").arg("version").output().is_err() {
997
+ return;
998
+ }
999
+
1000
+ let dir = tempdir().unwrap();
1001
+ fs::write(dir.path().join("go.mod"), "module ref_test\n\ngo 1.22\n").unwrap();
1002
+ fs::write(dir.path().join("models.go"), &code).unwrap();
1003
+ fs::write(
1004
+ dir.path().join("models_test.go"),
1005
+ r#"package models
1006
+
1007
+ import (
1008
+ "encoding/xml"
1009
+ "strings"
1010
+ "testing"
1011
+ )
1012
+
1013
+ func TestNamespacedElementRef(t *testing.T) {
1014
+ // 1. Default namespace instance
1015
+ xml1 := `<Container xmlns="urn:audit:ref"><Child>abc</Child></Container>`
1016
+ var c1 Container
1017
+ if err := xml.Unmarshal([]byte(xml1), &c1); err != nil {
1018
+ t.Fatalf("unmarshal xml1 failed: %v", err)
1019
+ }
1020
+ if c1.Child != "abc" {
1021
+ t.Fatalf("expected Child 'abc', got %q", c1.Child)
1022
+ }
1023
+
1024
+ // 2. Prefixed namespace instance (schema prefix t)
1025
+ xml2 := `<t:Container xmlns:t="urn:audit:ref"><t:Child>abc</t:Child></t:Container>`
1026
+ var c2 Container
1027
+ if err := xml.Unmarshal([]byte(xml2), &c2); err != nil {
1028
+ t.Fatalf("unmarshal xml2 failed: %v", err)
1029
+ }
1030
+ if c2.Child != "abc" {
1031
+ t.Fatalf("expected Child 'abc', got %q", c2.Child)
1032
+ }
1033
+
1034
+ // 3. Alternate prefix instance (prefix p)
1035
+ xml3 := `<p:Container xmlns:p="urn:audit:ref"><p:Child>abc</p:Child></p:Container>`
1036
+ var c3 Container
1037
+ if err := xml.Unmarshal([]byte(xml3), &c3); err != nil {
1038
+ t.Fatalf("unmarshal xml3 failed: %v", err)
1039
+ }
1040
+ if c3.Child != "abc" {
1041
+ t.Fatalf("expected Child 'abc', got %q", c3.Child)
1042
+ }
1043
+
1044
+ // 4. Foreign namespace URI with same local child name -> must NOT populate Child
1045
+ xml4 := `<Container xmlns="urn:audit:ref"><Child xmlns="urn:audit:other">abc</Child></Container>`
1046
+ var c4 Container
1047
+ if err := xml.Unmarshal([]byte(xml4), &c4); err != nil {
1048
+ t.Fatalf("unmarshal xml4 failed: %v", err)
1049
+ }
1050
+ if c4.Child != "" {
1051
+ t.Fatalf("expected Child to remain empty for foreign namespace, got %q", c4.Child)
1052
+ }
1053
+
1054
+ // 5. Roundtrip serialization preserves namespace
1055
+ data, err := xml.Marshal(c1)
1056
+ if err != nil {
1057
+ t.Fatalf("marshal failed: %v", err)
1058
+ }
1059
+ dataStr := string(data)
1060
+ if !strings.Contains(dataStr, "Child") || !strings.Contains(dataStr, "urn:audit:ref") {
1061
+ t.Fatalf("marshaled XML missing Child or namespace: %s", dataStr)
1062
+ }
1063
+ }
1064
+ "#,
1065
+ )
1066
+ .unwrap();
1067
+
1068
+ let output = Command::new("go")
1069
+ .args(["test", "-v", "./..."])
1070
+ .current_dir(dir.path())
1071
+ .output()
1072
+ .expect("go test failed to execute");
1073
+
1074
+ assert!(
1075
+ output.status.success(),
1076
+ "go test failed: stdout:\n{}\nstderr:\n{}",
1077
+ String::from_utf8_lossy(&output.stdout),
1078
+ String::from_utf8_lossy(&output.stderr)
1079
+ );
1080
+ }
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "polyxml"
7
- version = "0.33.3"
7
+ version = "0.33.4"
8
8
  description = "High-performance, polyglot XML data-binding engine built in Rust"
9
9
  authors = [
10
10
  { name = "Bailey Nguyen", email = "bailey.tan.nguyen@gmail.com" }
File without changes