polyxml 0.30.7__tar.gz → 0.31.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.
Files changed (72) hide show
  1. {polyxml-0.30.7 → polyxml-0.31.0}/Cargo.lock +6 -6
  2. {polyxml-0.30.7 → polyxml-0.31.0}/Cargo.toml +1 -1
  3. {polyxml-0.30.7 → polyxml-0.31.0}/PKG-INFO +1 -1
  4. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/ir/mod.rs +318 -1
  5. {polyxml-0.30.7 → polyxml-0.31.0}/pyproject.toml +1 -1
  6. {polyxml-0.30.7 → polyxml-0.31.0}/README.md +0 -0
  7. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/Cargo.toml +0 -0
  8. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/README.md +0 -0
  9. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
  10. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
  11. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
  12. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
  13. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
  14. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
  15. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
  16. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
  17. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
  18. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/mod.rs +0 -0
  19. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/python/aot.rs +0 -0
  20. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
  21. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
  22. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
  23. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/converters.rs +0 -0
  24. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/error.rs +0 -0
  25. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
  26. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/json.rs +0 -0
  27. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/lib.rs +0 -0
  28. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/parser.rs +0 -0
  29. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/schema.rs +0 -0
  30. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/schema_parser/mod.rs +0 -0
  31. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/serializer.rs +0 -0
  32. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/transcoder.rs +0 -0
  33. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/src/value.rs +0 -0
  34. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
  35. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
  36. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
  37. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
  38. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_conformance.rs +0 -0
  39. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_core.rs +0 -0
  40. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
  41. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
  42. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
  43. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
  44. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_json.rs +0 -0
  45. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
  46. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
  47. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
  48. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
  49. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
  50. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
  51. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
  52. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
  53. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_security.rs +0 -0
  54. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
  55. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
  56. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
  57. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
  58. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/Cargo.toml +0 -0
  59. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/README.md +0 -0
  60. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
  61. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/src/lib.rs +0 -0
  62. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/tests/test_conformance.py +0 -0
  63. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/tests/test_generated_models.py +0 -0
  64. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/tests/test_json.py +0 -0
  65. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
  66. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/tests/test_polyxml.py +0 -0
  67. {polyxml-0.30.7 → polyxml-0.31.0}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
  68. {polyxml-0.30.7 → polyxml-0.31.0}/python/polyxml/AGENT_GUIDE.md +0 -0
  69. {polyxml-0.30.7 → polyxml-0.31.0}/python/polyxml/__init__.py +0 -0
  70. {polyxml-0.30.7 → polyxml-0.31.0}/python/polyxml/compat/__init__.py +0 -0
  71. {polyxml-0.30.7 → polyxml-0.31.0}/python/polyxml/compat/xsdata.py +0 -0
  72. {polyxml-0.30.7 → polyxml-0.31.0}/python/polyxml/py.typed +0 -0
@@ -608,7 +608,7 @@ dependencies = [
608
608
 
609
609
  [[package]]
610
610
  name = "polyxml"
611
- version = "0.30.7"
611
+ version = "0.31.0"
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.30.7"
632
+ version = "0.31.0"
633
633
  dependencies = [
634
634
  "polyxml",
635
635
  ]
636
636
 
637
637
  [[package]]
638
638
  name = "polyxml-cli"
639
- version = "0.30.7"
639
+ version = "0.31.0"
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.30.7"
653
+ version = "0.31.0"
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.30.7"
663
+ version = "0.31.0"
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.30.7"
673
+ version = "0.31.0"
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.30.7"
6
+ version = "0.31.0"
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.30.7
3
+ Version: 0.31.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -1,7 +1,7 @@
1
1
  pub mod tarjan;
2
2
 
3
3
  use serde::{Deserialize, Serialize};
4
- use std::collections::{BTreeMap, HashMap};
4
+ use std::collections::{BTreeMap, BTreeSet, HashMap};
5
5
  use std::fmt;
6
6
 
7
7
  /// Fully qualified XML Name (Namespace URI + Local Name).
@@ -467,6 +467,161 @@ pub struct SchemaIR {
467
467
  }
468
468
 
469
469
  impl SchemaIR {
470
+ /// Keep the selected global elements and all types that can occur beneath them.
471
+ /// The schema is parsed in full before this operation, so references can be
472
+ /// followed across imports and includes.
473
+ pub fn select_root_elements(&self, roots: &[String]) -> Result<Self, String> {
474
+ if roots.is_empty() {
475
+ return Ok(self.clone());
476
+ }
477
+
478
+ let mut selected_elements = BTreeSet::new();
479
+ for name in roots {
480
+ let matches: Vec<_> = if let Some(qualified) = name.strip_prefix('{') {
481
+ let (namespace, local) = qualified.split_once('}').ok_or_else(|| {
482
+ format!("Invalid root element '{name}': expected {{namespace}}local-name")
483
+ })?;
484
+ if local.is_empty() {
485
+ return Err(format!("Invalid root element '{name}': missing local name"));
486
+ }
487
+ self.elements
488
+ .keys()
489
+ .filter(|q| {
490
+ q.namespace.as_deref().unwrap_or("") == namespace && q.local == local
491
+ })
492
+ .cloned()
493
+ .collect()
494
+ } else {
495
+ self.elements
496
+ .keys()
497
+ .filter(|q| q.local == *name)
498
+ .cloned()
499
+ .collect()
500
+ };
501
+ match matches.as_slice() {
502
+ [] => return Err(format!("Root element '{name}' was not found in the schema")),
503
+ [qname] => {
504
+ selected_elements.insert(qname.clone());
505
+ }
506
+ _ => {
507
+ return Err(format!(
508
+ "Root element '{name}' is ambiguous; use {{namespace}}local-name"
509
+ ))
510
+ }
511
+ }
512
+ }
513
+
514
+ let mut descendants: HashMap<QName, Vec<QName>> = HashMap::new();
515
+ for (qname, def) in &self.types {
516
+ let base = match def {
517
+ TypeDef::Struct(s) => s.base_type.as_ref(),
518
+ TypeDef::Simple(s) => named_ref(&s.base_type),
519
+ TypeDef::Enum(e) => named_ref(&e.base_type),
520
+ TypeDef::Union(_) => None,
521
+ };
522
+ if let Some(base) = base {
523
+ descendants
524
+ .entry(base.clone())
525
+ .or_default()
526
+ .push(qname.clone());
527
+ }
528
+ }
529
+
530
+ let mut selected_types = BTreeSet::new();
531
+ let mut pending_elements: Vec<_> = selected_elements.iter().cloned().collect();
532
+ let mut pending_types: Vec<(QName, bool)> = Vec::new();
533
+ let mut expanded_polymorphic = BTreeSet::new();
534
+ while !pending_elements.is_empty() || !pending_types.is_empty() {
535
+ while let Some(qname) = pending_elements.pop() {
536
+ if let Some(element) = self.elements.get(&qname) {
537
+ push_named_ref(&element.type_ref, true, &mut pending_types);
538
+ if let Some(head) = &element.substitution_group {
539
+ if selected_elements.insert(head.clone()) {
540
+ pending_elements.push(head.clone());
541
+ }
542
+ }
543
+ }
544
+ if let Some(members) = self.substitution_groups.get(&qname) {
545
+ for member in members {
546
+ if selected_elements.insert(member.clone()) {
547
+ pending_elements.push(member.clone());
548
+ }
549
+ }
550
+ }
551
+ }
552
+ if let Some((qname, polymorphic)) = pending_types.pop() {
553
+ if polymorphic && expanded_polymorphic.insert(qname.clone()) {
554
+ if let Some(children) = descendants.get(&qname) {
555
+ pending_types.extend(children.iter().cloned().map(|child| (child, true)));
556
+ }
557
+ }
558
+ if !selected_types.insert(qname.clone()) {
559
+ continue;
560
+ }
561
+ if let Some(def) = self.types.get(&qname) {
562
+ match def {
563
+ TypeDef::Struct(s) => {
564
+ if let Some(base) = &s.base_type {
565
+ pending_types.push((base.clone(), false));
566
+ }
567
+ for field in &s.fields {
568
+ push_named_ref(&field.type_ref, true, &mut pending_types);
569
+ if field.kind == FieldKind::Element {
570
+ let element = referenced_element_name(
571
+ field.namespace.as_deref(),
572
+ &field.xml_name,
573
+ );
574
+ if self.substitution_groups.contains_key(&element)
575
+ && selected_elements.insert(element.clone())
576
+ {
577
+ pending_elements.push(element);
578
+ }
579
+ }
580
+ }
581
+ }
582
+ TypeDef::Simple(s) => {
583
+ push_named_ref(&s.base_type, false, &mut pending_types)
584
+ }
585
+ TypeDef::Enum(e) => push_named_ref(&e.base_type, false, &mut pending_types),
586
+ TypeDef::Union(u) => {
587
+ for branch in &u.branches {
588
+ push_named_ref(&branch.type_ref, true, &mut pending_types);
589
+ let element = referenced_element_name(
590
+ branch.namespace.as_deref(),
591
+ &branch.xml_name,
592
+ );
593
+ if self.substitution_groups.contains_key(&element)
594
+ && selected_elements.insert(element.clone())
595
+ {
596
+ pending_elements.push(element);
597
+ }
598
+ }
599
+ }
600
+ }
601
+ }
602
+ }
603
+ }
604
+
605
+ let mut result = self.clone();
606
+ result
607
+ .types
608
+ .retain(|qname, _| selected_types.contains(qname));
609
+ result
610
+ .elements
611
+ .retain(|qname, _| selected_elements.contains(qname));
612
+ result
613
+ .external_types
614
+ .retain(|qname, _| selected_types.contains(qname));
615
+ result.substitution_groups.retain(|head, members| {
616
+ if !selected_elements.contains(head) {
617
+ return false;
618
+ }
619
+ members.retain(|member| selected_elements.contains(member));
620
+ !members.is_empty()
621
+ });
622
+ Ok(result)
623
+ }
624
+
470
625
  pub fn is_external_type(&self, qname: &QName) -> bool {
471
626
  if qname
472
627
  .namespace
@@ -520,3 +675,165 @@ impl SchemaIR {
520
675
  tarjan::resolve_cycles(self);
521
676
  }
522
677
  }
678
+
679
+ fn named_ref(type_ref: &TypeRef) -> Option<&QName> {
680
+ match type_ref {
681
+ TypeRef::Named(qname) => Some(qname),
682
+ TypeRef::Boxed(inner) | TypeRef::List(inner) => named_ref(inner),
683
+ TypeRef::Primitive(_) => None,
684
+ }
685
+ }
686
+
687
+ fn push_named_ref(type_ref: &TypeRef, polymorphic: bool, pending: &mut Vec<(QName, bool)>) {
688
+ if let Some(qname) = named_ref(type_ref) {
689
+ pending.push((qname.clone(), polymorphic));
690
+ }
691
+ }
692
+
693
+ fn referenced_element_name(namespace: Option<&str>, xml_name: &str) -> QName {
694
+ let local = xml_name.rsplit(':').next().unwrap_or(xml_name);
695
+ QName::new(namespace, local)
696
+ }
697
+
698
+ #[cfg(test)]
699
+ mod root_selection_tests {
700
+ use super::*;
701
+
702
+ fn structure(name: &str, base: Option<&str>, fields: Vec<FieldDef>) -> TypeDef {
703
+ TypeDef::Struct(StructDef {
704
+ qname: QName::new(Some("urn:test"), name),
705
+ base_type: base.map(|name| QName::new(Some("urn:test"), name)),
706
+ is_abstract: false,
707
+ is_mixed: false,
708
+ fields,
709
+ documentation: None,
710
+ })
711
+ }
712
+
713
+ fn element(name: &str, ty: &str) -> ElementDef {
714
+ ElementDef {
715
+ qname: QName::new(Some("urn:test"), name),
716
+ type_ref: TypeRef::named(QName::new(Some("urn:test"), ty)),
717
+ substitution_group: None,
718
+ nillable: false,
719
+ documentation: None,
720
+ }
721
+ }
722
+
723
+ #[test]
724
+ fn keeps_references_descendants_and_substitutions() {
725
+ let mut ir = SchemaIR::new();
726
+ let mut field = FieldDef::new(
727
+ "item",
728
+ "Item",
729
+ FieldKind::Element,
730
+ TypeRef::List(Box::new(TypeRef::named(QName::new(
731
+ Some("urn:test"),
732
+ "Choice",
733
+ )))),
734
+ );
735
+ field.namespace = Some("urn:test".to_string());
736
+ ir.add_type(structure("RootType", None, vec![field]));
737
+ ir.add_type(structure("Base", None, vec![]));
738
+ ir.add_type(structure("Derived", Some("Base"), vec![]));
739
+ ir.add_type(TypeDef::Union(UnionDef {
740
+ qname: QName::new(Some("urn:test"), "Choice"),
741
+ branches: vec![UnionBranch {
742
+ variant_name: "Base".into(),
743
+ xml_name: "Base".into(),
744
+ namespace: Some("urn:test".into()),
745
+ type_ref: TypeRef::named(QName::new(Some("urn:test"), "Base")),
746
+ documentation: None,
747
+ }],
748
+ documentation: None,
749
+ }));
750
+ ir.add_type(structure("Unrelated", None, vec![]));
751
+ ir.add_element(element("Root", "RootType"));
752
+ ir.add_element(element("UnrelatedRoot", "Unrelated"));
753
+ let mut member = element("Member", "Derived");
754
+ member.substitution_group = Some(QName::new(Some("urn:test"), "Root"));
755
+ ir.add_element(member);
756
+
757
+ let selected = ir.select_root_elements(&["Root".into()]).unwrap();
758
+ assert_eq!(selected.elements.len(), 2);
759
+ assert_eq!(selected.types.len(), 4);
760
+ assert!(selected
761
+ .types
762
+ .contains_key(&QName::new(Some("urn:test"), "Derived")));
763
+ assert!(!selected
764
+ .types
765
+ .contains_key(&QName::new(Some("urn:test"), "Unrelated")));
766
+ let combined = ir
767
+ .select_root_elements(&["Root".into(), "UnrelatedRoot".into()])
768
+ .unwrap();
769
+ assert_eq!(combined.elements.len(), 3);
770
+ assert!(combined
771
+ .types
772
+ .contains_key(&QName::new(Some("urn:test"), "Unrelated")));
773
+ }
774
+
775
+ #[test]
776
+ fn rejects_missing_and_ambiguous_roots() {
777
+ let mut ir = SchemaIR::new();
778
+ ir.add_element(element("Root", "RootType"));
779
+ let mut second = element("Root", "RootType");
780
+ second.qname.namespace = Some("urn:other".into());
781
+ ir.add_element(second);
782
+ assert!(ir
783
+ .select_root_elements(&["Root".into()])
784
+ .unwrap_err()
785
+ .contains("ambiguous"));
786
+ assert_eq!(
787
+ ir.select_root_elements(&["{urn:test}Root".into()])
788
+ .unwrap()
789
+ .elements
790
+ .len(),
791
+ 1
792
+ );
793
+ assert!(ir
794
+ .select_root_elements(&["Missing".into()])
795
+ .unwrap_err()
796
+ .contains("not found"));
797
+ }
798
+
799
+ #[test]
800
+ fn inherited_base_does_not_select_sibling_types() {
801
+ let mut ir = SchemaIR::new();
802
+ ir.add_type(structure("CommonBase", None, vec![]));
803
+ ir.add_type(structure("SelectedType", Some("CommonBase"), vec![]));
804
+ ir.add_type(structure("SiblingType", Some("CommonBase"), vec![]));
805
+ ir.add_element(element("Selected", "SelectedType"));
806
+ let selected = ir.select_root_elements(&["Selected".into()]).unwrap();
807
+ assert!(selected
808
+ .types
809
+ .contains_key(&QName::new(Some("urn:test"), "CommonBase")));
810
+ assert!(selected
811
+ .types
812
+ .contains_key(&QName::new(Some("urn:test"), "SelectedType")));
813
+ assert!(!selected
814
+ .types
815
+ .contains_key(&QName::new(Some("urn:test"), "SiblingType")));
816
+ }
817
+
818
+ #[test]
819
+ fn field_reference_keeps_substitution_group_members() {
820
+ let xsd = r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
821
+ xmlns:t="urn:test" targetNamespace="urn:test" elementFormDefault="qualified">
822
+ <xs:element name="Head" type="xs:string" abstract="true"/>
823
+ <xs:element name="Member" type="xs:string" substitutionGroup="t:Head"/>
824
+ <xs:complexType name="ContainerType"><xs:sequence>
825
+ <xs:element ref="t:Head"/>
826
+ </xs:sequence></xs:complexType>
827
+ <xs:element name="Container" type="t:ContainerType"/>
828
+ </xs:schema>"#;
829
+ let mut parser = crate::schema_parser::XsdParser::new();
830
+ let ir = parser.parse_str(xsd).unwrap();
831
+ let selected = ir.select_root_elements(&["Container".into()]).unwrap();
832
+ assert!(selected
833
+ .elements
834
+ .contains_key(&QName::new(Some("urn:test"), "Head")));
835
+ assert!(selected
836
+ .elements
837
+ .contains_key(&QName::new(Some("urn:test"), "Member")));
838
+ }
839
+ }
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "polyxml"
7
- version = "0.30.7"
7
+ version = "0.31.0"
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