1use core::ffi::c_void;
71use core::ptr;
72use std::os::raw::{c_char, c_int};
73
74use crate::abi::allocator;
75use crate::abi::structs::*;
76use crate::abi::types::xmlElementType::*;
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum XsdComponentType {
90 Schema,
93 Element,
95 Attribute,
97 ComplexType,
99 SimpleType,
101 SimpleContent,
103 ComplexContent,
105 Sequence,
107 Choice,
109 All,
111 Restriction,
113 Extension,
115 List,
117 Union,
119 Annotation,
121 Any,
123 AnyAttribute,
125 Group,
127 AttributeGroup,
129 Notation,
131 Unique,
133 Key,
135 KeyRef,
137 Selector,
139 Field,
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
154pub enum XsdDatatypeKind {
155 String,
158 Boolean,
160 Decimal,
163 Float,
166 Double,
169 Duration,
172 DateTime,
174 Time,
176 Date,
178 GYearMonth,
180 GYear,
182 GMonthDay,
184 GDay,
186 GMonth,
188 HexBinary,
191 Base64Binary,
193 AnyURI,
195 QName,
197 Notation,
200 NormalizedString,
204 Token,
207 Language,
210 Nmtoken,
212 Nmtokens,
214 Name,
216 NCName,
218 Id,
220 Idref,
222 Idrefs,
224 Entity,
226 Entities,
228 Integer,
231 NonPositiveInteger,
233 NegativeInteger,
235 Long,
237 Int,
239 Short,
241 Byte,
243 NonNegativeInteger,
245 UnsignedLong,
247 UnsignedInt,
249 UnsignedShort,
251 UnsignedByte,
253 PositiveInteger,
255 FacetPattern,
258 FacetEnumeration,
261 FacetMinInclusive,
263 FacetMaxInclusive,
265 FacetMinExclusive,
267 FacetMaxExclusive,
269 FacetMinLength,
271 FacetMaxLength,
273 FacetLength,
275 FacetWhiteSpace,
278 FacetFractionDigits,
281 FacetTotalDigits,
283}
284
285#[derive(Debug, Clone)]
294pub struct XsdComponent {
295 pub component_type: XsdComponentType,
297 pub name: Option<String>,
300 pub target_namespace: Option<String>,
302 pub children: Vec<XsdComponent>,
304 pub attributes: Vec<XsdComponent>,
306 pub datatype: Option<XsdDatatypeKind>,
309 pub facets: Vec<(XsdDatatypeKind, String)>,
311 pub base: Option<String>,
314 pub min_occurs: i32,
317 pub max_occurs: i32,
319 pub ref_name: Option<String>,
322 pub substitution_group: Option<String>,
324 pub is_abstract: bool,
326 pub is_final: bool,
328 pub block: Vec<String>,
330 pub mixed: bool,
332 pub form: Option<String>,
335}
336
337impl XsdComponent {
338 pub const fn new(component_type: XsdComponentType) -> Self {
342 Self {
343 component_type,
344 name: None,
345 target_namespace: None,
346 children: Vec::new(),
347 attributes: Vec::new(),
348 datatype: None,
349 facets: Vec::new(),
350 base: None,
351 min_occurs: 1,
352 max_occurs: 1,
353 ref_name: None,
354 substitution_group: None,
355 is_abstract: false,
356 is_final: false,
357 block: Vec::new(),
358 mixed: false,
359 form: None,
360 }
361 }
362}
363
364#[derive(Debug, Clone)]
372pub struct XsdSchema {
373 pub components: Vec<XsdComponent>,
375 pub target_namespace: Option<String>,
377 pub element_form_default: Option<String>,
379 pub attribute_form_default: Option<String>,
381 pub errors: Vec<String>,
383}
384
385impl XsdSchema {
386 pub const fn new() -> Self {
388 Self {
389 components: Vec::new(),
390 target_namespace: None,
391 element_form_default: None,
392 attribute_form_default: None,
393 errors: Vec::new(),
394 }
395 }
396}
397
398impl Default for XsdSchema {
399 fn default() -> Self {
400 Self::new()
401 }
402}
403
404#[derive(Debug)]
413pub struct XsdValidCtxt {
414 pub schema: Option<XsdSchema>,
416 pub errors: Vec<String>,
418 pub nb_errors: i32,
420}
421
422impl XsdValidCtxt {
423 pub const fn new() -> Self {
425 Self {
426 schema: None,
427 errors: Vec::new(),
428 nb_errors: 0,
429 }
430 }
431}
432
433impl Default for XsdValidCtxt {
434 fn default() -> Self {
435 Self::new()
436 }
437}
438
439unsafe fn get_node_text(node: *mut _xmlNode) -> String {
449 if node.is_null() {
450 return String::new();
451 }
452 let mut result = String::new();
453 unsafe {
454 let mut child = (*node).children;
455 while !child.is_null() {
456 if ((*child).type_ == XML_TEXT_NODE as c_int
457 || (*child).type_ == XML_CDATA_SECTION_NODE as c_int)
458 && !(*child).content.is_null()
459 {
460 let content = (*child).content;
461 let mut len = 0;
462 while *content.add(len) != 0 {
463 len += 1;
464 }
465 let slice = std::slice::from_raw_parts(content, len);
466 result.push_str(&String::from_utf8_lossy(slice));
467 }
468 child = (*child).next;
469 }
470 }
471 result
472}
473
474unsafe fn get_attr(node: *mut _xmlNode, name: &str) -> Option<String> {
480 if node.is_null() {
481 return None;
482 }
483 unsafe {
484 let mut prop = (*node).properties;
485 while !prop.is_null() {
486 let prop_name = (*prop).name;
487 if !prop_name.is_null() {
488 let mut len = 0;
489 while *prop_name.add(len) != 0 {
490 len += 1;
491 }
492 let slice = std::slice::from_raw_parts(prop_name, len);
493 if let Ok(s) = std::str::from_utf8(slice) {
494 if s == name {
495 return Some(get_node_text(prop as *mut _xmlNode));
496 }
497 }
498 }
499 prop = (*prop).next;
500 }
501 }
502 None
503}
504
505unsafe fn get_attr_bool(node: *mut _xmlNode, name: &str) -> bool {
511 unsafe {
512 match get_attr(node, name) {
513 Some(v) => v == "true" || v == "1",
514 None => false,
515 }
516 }
517}
518
519#[allow(dead_code)]
525unsafe fn get_attr_int(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
526 unsafe {
527 match get_attr(node, name) {
528 Some(v) => v.parse::<i32>().unwrap_or(default),
529 None => default,
530 }
531 }
532}
533
534unsafe fn get_attr_occurs(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
540 unsafe {
541 match get_attr(node, name) {
542 Some(v) => {
543 if v == "unbounded" {
544 -1
545 } else {
546 v.parse::<i32>().unwrap_or(default)
547 }
548 }
549 None => default,
550 }
551 }
552}
553
554unsafe fn node_is(node: *mut _xmlNode, local_name: &str) -> bool {
560 if node.is_null() {
561 return false;
562 }
563 unsafe {
564 let name = (*node).name;
565 if name.is_null() {
566 return false;
567 }
568 let mut len = 0;
569 while *name.add(len) != 0 {
570 len += 1;
571 }
572 let slice = std::slice::from_raw_parts(name, len);
573 if let Ok(s) = std::str::from_utf8(slice) {
574 let local = if let Some(pos) = s.find(':') {
576 &s[pos + 1..]
577 } else {
578 s
579 };
580 return local == local_name;
581 }
582 }
583 false
584}
585
586fn parse_datatype_kind(name: &str) -> Option<XsdDatatypeKind> {
588 let local = if let Some(pos) = name.find(':') {
590 &name[pos + 1..]
591 } else {
592 name
593 };
594
595 match local {
596 "string" => Some(XsdDatatypeKind::String),
597 "boolean" => Some(XsdDatatypeKind::Boolean),
598 "decimal" => Some(XsdDatatypeKind::Decimal),
599 "float" => Some(XsdDatatypeKind::Float),
600 "double" => Some(XsdDatatypeKind::Double),
601 "duration" => Some(XsdDatatypeKind::Duration),
602 "dateTime" => Some(XsdDatatypeKind::DateTime),
603 "time" => Some(XsdDatatypeKind::Time),
604 "date" => Some(XsdDatatypeKind::Date),
605 "gYearMonth" => Some(XsdDatatypeKind::GYearMonth),
606 "gYear" => Some(XsdDatatypeKind::GYear),
607 "gMonthDay" => Some(XsdDatatypeKind::GMonthDay),
608 "gDay" => Some(XsdDatatypeKind::GDay),
609 "gMonth" => Some(XsdDatatypeKind::GMonth),
610 "hexBinary" => Some(XsdDatatypeKind::HexBinary),
611 "base64Binary" => Some(XsdDatatypeKind::Base64Binary),
612 "anyURI" => Some(XsdDatatypeKind::AnyURI),
613 "QName" => Some(XsdDatatypeKind::QName),
614 "NOTATION" => Some(XsdDatatypeKind::Notation),
615 "normalizedString" => Some(XsdDatatypeKind::NormalizedString),
616 "token" => Some(XsdDatatypeKind::Token),
617 "language" => Some(XsdDatatypeKind::Language),
618 "NMTOKEN" => Some(XsdDatatypeKind::Nmtoken),
619 "NMTOKENS" => Some(XsdDatatypeKind::Nmtokens),
620 "Name" => Some(XsdDatatypeKind::Name),
621 "NCName" => Some(XsdDatatypeKind::NCName),
622 "ID" => Some(XsdDatatypeKind::Id),
623 "IDREF" => Some(XsdDatatypeKind::Idref),
624 "IDREFS" => Some(XsdDatatypeKind::Idrefs),
625 "ENTITY" => Some(XsdDatatypeKind::Entity),
626 "ENTITIES" => Some(XsdDatatypeKind::Entities),
627 "integer" => Some(XsdDatatypeKind::Integer),
628 "nonPositiveInteger" => Some(XsdDatatypeKind::NonPositiveInteger),
629 "negativeInteger" => Some(XsdDatatypeKind::NegativeInteger),
630 "long" => Some(XsdDatatypeKind::Long),
631 "int" => Some(XsdDatatypeKind::Int),
632 "short" => Some(XsdDatatypeKind::Short),
633 "byte" => Some(XsdDatatypeKind::Byte),
634 "nonNegativeInteger" => Some(XsdDatatypeKind::NonNegativeInteger),
635 "unsignedLong" => Some(XsdDatatypeKind::UnsignedLong),
636 "unsignedInt" => Some(XsdDatatypeKind::UnsignedInt),
637 "unsignedShort" => Some(XsdDatatypeKind::UnsignedShort),
638 "unsignedByte" => Some(XsdDatatypeKind::UnsignedByte),
639 "positiveInteger" => Some(XsdDatatypeKind::PositiveInteger),
640 _ => None,
641 }
642}
643
644fn parse_facet_kind(name: &str) -> Option<XsdDatatypeKind> {
646 match name {
647 "pattern" => Some(XsdDatatypeKind::FacetPattern),
648 "enumeration" => Some(XsdDatatypeKind::FacetEnumeration),
649 "minInclusive" => Some(XsdDatatypeKind::FacetMinInclusive),
650 "maxInclusive" => Some(XsdDatatypeKind::FacetMaxInclusive),
651 "minExclusive" => Some(XsdDatatypeKind::FacetMinExclusive),
652 "maxExclusive" => Some(XsdDatatypeKind::FacetMaxExclusive),
653 "minLength" => Some(XsdDatatypeKind::FacetMinLength),
654 "maxLength" => Some(XsdDatatypeKind::FacetMaxLength),
655 "length" => Some(XsdDatatypeKind::FacetLength),
656 "whiteSpace" => Some(XsdDatatypeKind::FacetWhiteSpace),
657 "fractionDigits" => Some(XsdDatatypeKind::FacetFractionDigits),
658 "totalDigits" => Some(XsdDatatypeKind::FacetTotalDigits),
659 _ => None,
660 }
661}
662
663pub fn xsd_parse(xml_doc: &str) -> Result<XsdSchema, String> {
682 let doc_ptr = unsafe {
684 crate::abi::exports_xml2::xmlReadMemory(
685 xml_doc.as_ptr() as *const c_char,
686 xml_doc.len() as c_int,
687 c"schema.xsd".as_ptr() as *const c_char,
688 ptr::null(),
689 0,
690 )
691 };
692
693 if doc_ptr.is_null() {
694 return Err("Failed to parse schema XML document".to_string());
695 }
696
697 let result = unsafe { xsd_parse_schema_doc(doc_ptr) };
698 unsafe {
699 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
700 }
701 result
702}
703
704unsafe fn xsd_parse_schema_doc(doc: *mut _xmlDoc) -> Result<XsdSchema, String> {
710 unsafe {
711 let root = (*doc).children;
712 if root.is_null() {
713 return Err("Schema document has no root element".to_string());
714 }
715
716 let mut schema_node = root;
718 while !schema_node.is_null() && !node_is(schema_node, "schema") {
719 schema_node = (*schema_node).next;
720 }
721
722 if schema_node.is_null() {
723 return Err("Schema document root is not <schema>".to_string());
724 }
725
726 Ok(xsd_parse_schema_node(schema_node))
727 }
728}
729
730unsafe fn xsd_parse_schema_node(node: *mut _xmlNode) -> XsdSchema {
736 unsafe {
737 let mut schema = XsdSchema::new();
738 schema.target_namespace = get_attr(node, "targetNamespace");
739 schema.element_form_default = get_attr(node, "elementFormDefault");
740 schema.attribute_form_default = get_attr(node, "attributeFormDefault");
741
742 let mut child = (*node).children;
744 while !child.is_null() {
745 if (*child).type_ == XML_ELEMENT_NODE as c_int {
746 let comp = xsd_parse_component(child, &schema);
747 if comp.component_type != XsdComponentType::Annotation {
748 schema.components.push(comp);
749 }
750 }
751 child = (*child).next;
752 }
753
754 schema
755 }
756}
757
758unsafe fn xsd_parse_component(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
764 unsafe {
765 let name_str = if !(*node).name.is_null() {
767 let mut len = 0;
768 while *(*node).name.add(len) != 0 {
769 len += 1;
770 }
771 let slice = std::slice::from_raw_parts((*node).name, len);
772 if let Ok(s) = std::str::from_utf8(slice) {
773 if let Some(pos) = s.find(':') {
774 s[pos + 1..].to_string()
775 } else {
776 s.to_string()
777 }
778 } else {
779 String::new()
780 }
781 } else {
782 String::new()
783 };
784
785 match name_str.as_str() {
786 "element" => xsd_parse_element(node, schema),
787 "attribute" => xsd_parse_attribute_node(node, schema),
788 "complexType" => xsd_parse_complex_type(node, schema),
789 "simpleType" => xsd_parse_simple_type(node, schema),
790 "sequence" => xsd_parse_model_group(node, XsdComponentType::Sequence, schema),
791 "choice" => xsd_parse_model_group(node, XsdComponentType::Choice, schema),
792 "all" => xsd_parse_model_group(node, XsdComponentType::All, schema),
793 "restriction" => xsd_parse_restriction(node, schema),
794 "extension" => xsd_parse_extension(node, schema),
795 "list" => xsd_parse_list(node, schema),
796 "union" => xsd_parse_union(node, schema),
797 "annotation" => xsd_parse_annotation(node),
798 "any" => xsd_parse_any(node, schema),
799 "anyAttribute" => XsdComponent::new(XsdComponentType::AnyAttribute),
800 "group" => xsd_parse_group(node, schema),
801 "attributeGroup" => xsd_parse_attribute_group(node, schema),
802 "unique" => xsd_parse_identity_constraint(node, XsdComponentType::Unique, schema),
803 "key" => xsd_parse_identity_constraint(node, XsdComponentType::Key, schema),
804 "keyref" => xsd_parse_identity_constraint(node, XsdComponentType::KeyRef, schema),
805 "pattern" | "enumeration" | "minInclusive" | "maxInclusive" | "minExclusive"
807 | "maxExclusive" | "minLength" | "maxLength" | "length" | "whiteSpace"
808 | "fractionDigits" | "totalDigits" => xsd_parse_facet(node),
809 "simpleContent" => xsd_parse_simple_content(node, schema),
811 "complexContent" => xsd_parse_complex_content(node, schema),
812 _ => {
813 let mut comp = XsdComponent::new(XsdComponentType::Schema);
815 if let Ok(s) = std::str::from_utf8(std::slice::from_raw_parts((*node).name, {
816 let mut len = 0;
817 while *(*node).name.add(len) != 0 {
818 len += 1;
819 }
820 len
821 })) {
822 comp.name = Some(s.to_string());
823 }
824 comp
825 }
826 }
827 }
828}
829
830unsafe fn xsd_parse_element(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
836 unsafe {
837 let mut comp = XsdComponent::new(XsdComponentType::Element);
838 comp.name = get_attr(node, "name");
839 comp.ref_name = get_attr(node, "ref");
840 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
841 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
842 comp.is_abstract = get_attr_bool(node, "abstract");
843 comp.is_final = get_attr_bool(node, "final");
844 comp.substitution_group = get_attr(node, "substitutionGroup");
845 comp.form = get_attr(node, "form");
846
847 if let Some(type_name) = get_attr(node, "type") {
849 comp.datatype = parse_datatype_kind(&type_name);
850 if comp.datatype.is_none() {
852 comp.base = Some(type_name);
853 }
854 }
855
856 let _default = get_attr(node, "default");
858 let _fixed = get_attr(node, "fixed");
859
860 let mut child = (*node).children;
862 while !child.is_null() {
863 if (*child).type_ == XML_ELEMENT_NODE as c_int {
864 let child_comp = xsd_parse_component(child, schema);
865 match child_comp.component_type {
866 XsdComponentType::ComplexType | XsdComponentType::SimpleType => {
867 if let Some(ref name) = child_comp.name {
869 comp.base = Some(name.clone());
870 }
871 comp.children.push(child_comp);
872 }
873 XsdComponentType::Annotation => {
874 }
876 _ => {
877 comp.children.push(child_comp);
878 }
879 }
880 }
881 child = (*child).next;
882 }
883
884 comp
885 }
886}
887
888unsafe fn xsd_parse_attribute_node(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
894 unsafe {
895 let mut comp = XsdComponent::new(XsdComponentType::Attribute);
896 comp.name = get_attr(node, "name");
897 comp.ref_name = get_attr(node, "ref");
898 comp.form = get_attr(node, "form");
899
900 if let Some(type_name) = get_attr(node, "type") {
902 comp.datatype = parse_datatype_kind(&type_name);
903 if comp.datatype.is_none() {
904 comp.base = Some(type_name);
905 }
906 }
907
908 let use_attr = get_attr(node, "use");
910 if let Some(ref use_val) = use_attr {
911 if use_val == "required" {
912 comp.min_occurs = 1;
913 } else if use_val == "prohibited" {
914 comp.min_occurs = 0;
915 comp.max_occurs = 0;
916 } else {
917 comp.min_occurs = 0;
919 }
920 } else {
921 comp.min_occurs = 0; }
923
924 let _default = get_attr(node, "default");
925 let _fixed = get_attr(node, "fixed");
926
927 let mut child = (*node).children;
929 while !child.is_null() {
930 if (*child).type_ == XML_ELEMENT_NODE as c_int {
931 let child_comp = xsd_parse_component(child, schema);
932 if child_comp.component_type == XsdComponentType::SimpleType {
933 if let Some(ref name) = child_comp.name {
934 comp.base = Some(name.clone());
935 }
936 comp.children.push(child_comp);
937 }
938 }
939 child = (*child).next;
940 }
941
942 comp
943 }
944}
945
946unsafe fn xsd_parse_complex_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
952 unsafe {
953 let mut comp = XsdComponent::new(XsdComponentType::ComplexType);
954 comp.name = get_attr(node, "name");
955 comp.mixed = get_attr_bool(node, "mixed");
956 comp.is_abstract = get_attr_bool(node, "abstract");
957 comp.is_final = get_attr_bool(node, "final");
958
959 let mut child = (*node).children;
961 while !child.is_null() {
962 if (*child).type_ == XML_ELEMENT_NODE as c_int {
963 let child_comp = xsd_parse_component(child, schema);
964 match child_comp.component_type {
965 XsdComponentType::SimpleContent
966 | XsdComponentType::ComplexContent
967 | XsdComponentType::Sequence
968 | XsdComponentType::Choice
969 | XsdComponentType::All
970 | XsdComponentType::Group
971 | XsdComponentType::Any
972 | XsdComponentType::Annotation => {
973 if child_comp.component_type == XsdComponentType::SimpleContent {
974 comp.children.extend(child_comp.children);
976 } else if child_comp.component_type == XsdComponentType::ComplexContent {
977 comp.children.extend(child_comp.children);
979 } else {
980 comp.children.push(child_comp);
981 }
982 }
983 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
984 comp.attributes.push(child_comp);
985 }
986 _ => {
987 comp.children.push(child_comp);
988 }
989 }
990 }
991 child = (*child).next;
992 }
993
994 comp
995 }
996}
997
998unsafe fn xsd_parse_simple_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1004 unsafe {
1005 let mut comp = XsdComponent::new(XsdComponentType::SimpleType);
1006 comp.name = get_attr(node, "name");
1007
1008 let mut child = (*node).children;
1010 while !child.is_null() {
1011 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1012 let child_comp = xsd_parse_component(child, schema);
1013 match child_comp.component_type {
1014 XsdComponentType::Restriction
1015 | XsdComponentType::List
1016 | XsdComponentType::Union => {
1017 comp.datatype = child_comp.datatype;
1018 comp.base = child_comp.base;
1019 comp.facets = child_comp.facets;
1020 comp.children.extend(child_comp.children);
1021 }
1022 _ => {}
1023 }
1024 }
1025 child = (*child).next;
1026 }
1027
1028 comp
1029 }
1030}
1031
1032unsafe fn xsd_parse_model_group(
1038 node: *mut _xmlNode,
1039 ctype: XsdComponentType,
1040 schema: &XsdSchema,
1041) -> XsdComponent {
1042 unsafe {
1043 let mut comp = XsdComponent::new(ctype);
1044 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1045 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1046
1047 let mut child = (*node).children;
1048 while !child.is_null() {
1049 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1050 let child_comp = xsd_parse_component(child, schema);
1051 match child_comp.component_type {
1052 XsdComponentType::Annotation => {}
1053 _ => {
1054 comp.children.push(child_comp);
1055 }
1056 }
1057 }
1058 child = (*child).next;
1059 }
1060
1061 comp
1062 }
1063}
1064
1065unsafe fn xsd_parse_restriction(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1071 unsafe {
1072 let mut comp = XsdComponent::new(XsdComponentType::Restriction);
1073 comp.base = get_attr(node, "base");
1074
1075 if let Some(ref base_name) = comp.base {
1077 comp.datatype = parse_datatype_kind(base_name);
1078 }
1079
1080 let mut child = (*node).children;
1082 while !child.is_null() {
1083 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1084 let child_comp = xsd_parse_component(child, schema);
1085 match child_comp.component_type {
1086 XsdComponentType::Sequence
1087 | XsdComponentType::Choice
1088 | XsdComponentType::All
1089 | XsdComponentType::Group
1090 | XsdComponentType::Any
1091 | XsdComponentType::Annotation => {
1092 comp.children.push(child_comp);
1093 }
1094 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1095 comp.attributes.push(child_comp);
1096 }
1097 XsdComponentType::SimpleType => {
1098 comp.children.push(child_comp);
1100 }
1101 _ => {
1102 if let Some(facet_kind) =
1104 parse_facet_kind(&format!("{:?}", child_comp.component_type))
1105 {
1106 if let Some(val) = get_attr(child, "value") {
1108 comp.facets.push((facet_kind, val));
1109 }
1110 }
1111 let name_str = if !(*child).name.is_null() {
1113 let mut len = 0;
1114 while *(*child).name.add(len) != 0 {
1115 len += 1;
1116 }
1117 let slice = std::slice::from_raw_parts((*child).name, len);
1118 std::str::from_utf8(slice)
1119 .ok()
1120 .map(|s| {
1121 if let Some(pos) = s.find(':') {
1122 s[pos + 1..].to_string()
1123 } else {
1124 s.to_string()
1125 }
1126 })
1127 .unwrap_or_default()
1128 } else {
1129 String::new()
1130 };
1131 if !name_str.is_empty() {
1132 if let Some(facet_kind) = parse_facet_kind(&name_str) {
1133 if let Some(val) = get_attr(child, "value") {
1134 comp.facets.push((facet_kind, val));
1135 }
1136 }
1137 }
1138 }
1139 }
1140 }
1141 child = (*child).next;
1142 }
1143
1144 comp
1145 }
1146}
1147
1148unsafe fn xsd_parse_extension(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1154 unsafe {
1155 let mut comp = XsdComponent::new(XsdComponentType::Extension);
1156 comp.base = get_attr(node, "base");
1157
1158 if let Some(ref base_name) = comp.base {
1159 comp.datatype = parse_datatype_kind(base_name);
1160 }
1161
1162 let mut child = (*node).children;
1164 while !child.is_null() {
1165 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1166 let child_comp = xsd_parse_component(child, schema);
1167 match child_comp.component_type {
1168 XsdComponentType::Sequence
1169 | XsdComponentType::Choice
1170 | XsdComponentType::All
1171 | XsdComponentType::Group
1172 | XsdComponentType::Any
1173 | XsdComponentType::Annotation => {
1174 comp.children.push(child_comp);
1175 }
1176 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1177 comp.attributes.push(child_comp);
1178 }
1179 _ => {}
1180 }
1181 }
1182 child = (*child).next;
1183 }
1184
1185 comp
1186 }
1187}
1188
1189unsafe fn xsd_parse_list(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1195 unsafe {
1196 let mut comp = XsdComponent::new(XsdComponentType::List);
1197
1198 if let Some(item_type) = get_attr(node, "itemType") {
1199 comp.base = Some(item_type.clone());
1200 comp.datatype = parse_datatype_kind(&item_type);
1201 }
1202
1203 let mut child = (*node).children;
1205 while !child.is_null() {
1206 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1207 let child_comp = xsd_parse_component(child, schema);
1208 if child_comp.component_type == XsdComponentType::SimpleType {
1209 comp.datatype = child_comp.datatype;
1210 comp.base = child_comp.base;
1211 comp.facets = child_comp.facets;
1212 }
1213 }
1214 child = (*child).next;
1215 }
1216
1217 comp
1218 }
1219}
1220
1221unsafe fn xsd_parse_union(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1227 unsafe {
1228 let mut comp = XsdComponent::new(XsdComponentType::Union);
1229
1230 if let Some(member_types) = get_attr(node, "memberTypes") {
1231 comp.base = Some(member_types);
1232 }
1233
1234 let mut child = (*node).children;
1235 while !child.is_null() {
1236 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1237 let child_comp = xsd_parse_component(child, schema);
1238 if child_comp.component_type == XsdComponentType::SimpleType {
1239 comp.children.push(child_comp);
1240 }
1241 }
1242 child = (*child).next;
1243 }
1244
1245 comp
1246 }
1247}
1248
1249unsafe fn xsd_parse_annotation(node: *mut _xmlNode) -> XsdComponent {
1255 unsafe {
1256 let mut comp = XsdComponent::new(XsdComponentType::Annotation);
1257
1258 let mut child = (*node).children;
1259 while !child.is_null() {
1260 if (*child).type_ == XML_ELEMENT_NODE as c_int
1261 && (node_is(child, "documentation") || node_is(child, "appinfo"))
1262 {
1263 let text = get_node_text(child);
1264 if !text.is_empty() {
1265 comp.facets.push((XsdDatatypeKind::String, text));
1266 }
1267 }
1268 child = (*child).next;
1269 }
1270
1271 comp
1272 }
1273}
1274
1275unsafe fn xsd_parse_any(node: *mut _xmlNode, _schema: &XsdSchema) -> XsdComponent {
1281 unsafe {
1282 let mut comp = XsdComponent::new(XsdComponentType::Any);
1283 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1284 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1285
1286 let namespace_attr = get_attr(node, "namespace");
1287 if let Some(ref ns) = namespace_attr {
1288 if ns != "##any" {
1289 comp.target_namespace = Some(ns.clone());
1290 }
1291 }
1292
1293 comp
1294 }
1295}
1296
1297unsafe fn xsd_parse_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1303 unsafe {
1304 let mut comp = XsdComponent::new(XsdComponentType::Group);
1305 comp.name = get_attr(node, "name");
1306 comp.ref_name = get_attr(node, "ref");
1307 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1308 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1309
1310 let mut child = (*node).children;
1311 while !child.is_null() {
1312 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1313 let child_comp = xsd_parse_component(child, schema);
1314 match child_comp.component_type {
1315 XsdComponentType::Annotation => {}
1316 _ => {
1317 comp.children.push(child_comp);
1318 }
1319 }
1320 }
1321 child = (*child).next;
1322 }
1323
1324 comp
1325 }
1326}
1327
1328unsafe fn xsd_parse_attribute_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1334 unsafe {
1335 let mut comp = XsdComponent::new(XsdComponentType::AttributeGroup);
1336 comp.name = get_attr(node, "name");
1337 comp.ref_name = get_attr(node, "ref");
1338
1339 let mut child = (*node).children;
1340 while !child.is_null() {
1341 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1342 let child_comp = xsd_parse_component(child, schema);
1343 match child_comp.component_type {
1344 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1345 comp.attributes.push(child_comp);
1346 }
1347 _ => {}
1348 }
1349 }
1350 child = (*child).next;
1351 }
1352
1353 comp
1354 }
1355}
1356
1357unsafe fn xsd_parse_facet(node: *mut _xmlNode) -> XsdComponent {
1363 unsafe {
1364 let name_str = if !(*node).name.is_null() {
1365 let mut len = 0;
1366 while *(*node).name.add(len) != 0 {
1367 len += 1;
1368 }
1369 let slice = std::slice::from_raw_parts((*node).name, len);
1370 std::str::from_utf8(slice)
1371 .ok()
1372 .map(|s| {
1373 if let Some(pos) = s.find(':') {
1374 s[pos + 1..].to_string()
1375 } else {
1376 s.to_string()
1377 }
1378 })
1379 .unwrap_or_default()
1380 } else {
1381 String::new()
1382 };
1383
1384 let facet_kind = parse_facet_kind(&name_str).unwrap_or(XsdDatatypeKind::String);
1385 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1386 let val = get_attr(node, "value").unwrap_or_default();
1387 comp.facets.push((facet_kind, val));
1388 comp.datatype = Some(facet_kind);
1389
1390 comp
1391 }
1392}
1393
1394unsafe fn xsd_parse_simple_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1400 unsafe {
1401 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1402
1403 let mut child = (*node).children;
1404 while !child.is_null() {
1405 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1406 let child_comp = xsd_parse_component(child, schema);
1407 match child_comp.component_type {
1408 XsdComponentType::Restriction | XsdComponentType::Extension => {
1409 comp.children.push(child_comp);
1410 }
1411 _ => {}
1412 }
1413 }
1414 child = (*child).next;
1415 }
1416
1417 comp
1418 }
1419}
1420
1421unsafe fn xsd_parse_complex_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1427 unsafe {
1428 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1429
1430 let mut child = (*node).children;
1431 while !child.is_null() {
1432 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1433 let child_comp = xsd_parse_component(child, schema);
1434 match child_comp.component_type {
1435 XsdComponentType::Restriction | XsdComponentType::Extension => {
1436 comp.children.push(child_comp);
1437 }
1438 _ => {}
1439 }
1440 }
1441 child = (*child).next;
1442 }
1443
1444 comp
1445 }
1446}
1447
1448unsafe fn xsd_parse_identity_constraint(
1454 node: *mut _xmlNode,
1455 ctype: XsdComponentType,
1456 schema: &XsdSchema,
1457) -> XsdComponent {
1458 unsafe {
1459 let mut comp = XsdComponent::new(ctype);
1460 comp.name = get_attr(node, "name");
1461
1462 if ctype == XsdComponentType::KeyRef {
1463 comp.ref_name = get_attr(node, "refer");
1464 }
1465
1466 let mut child = (*node).children;
1467 while !child.is_null() {
1468 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1469 let child_comp = xsd_parse_component(child, schema);
1470 match child_comp.component_type {
1471 XsdComponentType::Selector | XsdComponentType::Field => {
1472 comp.children.push(child_comp);
1473 }
1474 _ => {}
1475 }
1476 }
1477 child = (*child).next;
1478 }
1479
1480 comp
1481 }
1482}
1483
1484pub fn xsd_validate_datatype(
1494 kind: &XsdDatatypeKind,
1495 value: &str,
1496 facets: &[(XsdDatatypeKind, String)],
1497) -> bool {
1498 if !validate_base_type(kind, value) {
1500 return false;
1501 }
1502
1503 let mut has_enumeration = false;
1508 let mut enumeration_match = false;
1509
1510 for (facet_kind, facet_value) in facets {
1511 if *facet_kind == XsdDatatypeKind::FacetEnumeration {
1512 has_enumeration = true;
1513 if xsd_validate_facet(kind, value, facet_kind, facet_value) {
1514 enumeration_match = true;
1515 }
1516 } else if !xsd_validate_facet(kind, value, facet_kind, facet_value) {
1517 return false;
1518 }
1519 }
1520
1521 if has_enumeration && !enumeration_match {
1523 return false;
1524 }
1525
1526 true
1527}
1528
1529pub fn xsd_validate_facet(
1531 _kind: &XsdDatatypeKind,
1532 value: &str,
1533 facet_kind: &XsdDatatypeKind,
1534 facet_value: &str,
1535) -> bool {
1536 match facet_kind {
1537 XsdDatatypeKind::FacetPattern => {
1538 match facet_value {
1541 r"\d+" => value.chars().all(|c| c.is_ascii_digit()),
1542 r"\d*" => value.is_empty() || value.chars().all(|c| c.is_ascii_digit()),
1543 r"[a-zA-Z]+" => value.chars().all(|c| c.is_ascii_alphabetic()),
1544 r"[a-zA-Z]*" => value.is_empty() || value.chars().all(|c| c.is_ascii_alphabetic()),
1545 r"[a-zA-Z0-9]+" => value.chars().all(|c| c.is_ascii_alphanumeric()),
1546 r"[a-zA-Z0-9_\-]+" => value
1547 .chars()
1548 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
1549 r"[a-zA-Z_][a-zA-Z0-9_\-\.]*" => {
1550 if value.is_empty() {
1551 return false;
1552 }
1553 let first = value.chars().next().unwrap();
1554 if !first.is_ascii_alphabetic() && first != '_' {
1555 return false;
1556 }
1557 value
1558 .chars()
1559 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1560 }
1561 r"[a-zA-Z_][\w\-\.]*" => {
1562 if value.is_empty() {
1563 return false;
1564 }
1565 let first = value.chars().next().unwrap();
1566 if !first.is_ascii_alphabetic() && first != '_' {
1567 return false;
1568 }
1569 value
1570 .chars()
1571 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1572 }
1573 r"\i\c*" => {
1574 if value.is_empty() {
1576 return false;
1577 }
1578 let first = value.chars().next().unwrap();
1579 if !is_name_start_char(first) {
1580 return false;
1581 }
1582 value.chars().skip(1).all(is_name_char)
1583 }
1584 r"\c+" => {
1585 if value.is_empty() {
1586 return false;
1587 }
1588 value.chars().all(is_name_char)
1589 }
1590 _ => {
1592 if facet_value.starts_with('^') && facet_value.ends_with('$') {
1593 let inner = &facet_value[1..facet_value.len() - 1];
1594 simple_glob_match(inner, value)
1595 } else {
1596 true
1598 }
1599 }
1600 }
1601 }
1602 XsdDatatypeKind::FacetEnumeration => {
1603 value == facet_value
1605 }
1606 XsdDatatypeKind::FacetMinInclusive => {
1607 compare_strings(value, facet_value) != std::cmp::Ordering::Less
1608 }
1609 XsdDatatypeKind::FacetMaxInclusive => {
1610 compare_strings(value, facet_value) != std::cmp::Ordering::Greater
1611 }
1612 XsdDatatypeKind::FacetMinExclusive => {
1613 compare_strings(value, facet_value) == std::cmp::Ordering::Greater
1614 }
1615 XsdDatatypeKind::FacetMaxExclusive => {
1616 compare_strings(value, facet_value) == std::cmp::Ordering::Less
1617 }
1618 XsdDatatypeKind::FacetMinLength => {
1619 let min = facet_value.parse::<usize>().unwrap_or(0);
1620 value.chars().count() >= min
1621 }
1622 XsdDatatypeKind::FacetMaxLength => {
1623 let max = facet_value.parse::<usize>().unwrap_or(usize::MAX);
1624 value.chars().count() <= max
1625 }
1626 XsdDatatypeKind::FacetLength => {
1627 let len = facet_value.parse::<usize>().unwrap_or(0);
1628 value.chars().count() == len
1629 }
1630 XsdDatatypeKind::FacetWhiteSpace => {
1631 match facet_value {
1633 "replace" => {
1634 true
1637 }
1638 "collapse" => {
1639 true
1641 }
1642 _ => true,
1643 }
1644 }
1645 XsdDatatypeKind::FacetFractionDigits | XsdDatatypeKind::FacetTotalDigits => {
1646 value.parse::<f64>().is_ok()
1648 }
1649 _ => true,
1650 }
1651}
1652
1653fn simple_glob_match(pattern: &str, value: &str) -> bool {
1655 let pattern_chars: Vec<char> = pattern.chars().collect();
1656 let value_chars: Vec<char> = value.chars().collect();
1657
1658 let mut pi = 0;
1659 let mut vi = 0;
1660 let mut backtrack_p = None;
1661 let mut backtrack_v = 0;
1662
1663 while vi < value_chars.len() {
1664 if pi < pattern_chars.len()
1665 && (pattern_chars[pi] == value_chars[vi] || pattern_chars[pi] == '.')
1666 {
1667 pi += 1;
1668 vi += 1;
1669 } else if pi < pattern_chars.len() && pattern_chars[pi] == '*' {
1670 backtrack_p = Some(pi);
1671 backtrack_v = vi + 1;
1672 pi += 1;
1673 } else if pi < pattern_chars.len() && pattern_chars[pi] == '+' {
1674 if pi + 1 < pattern_chars.len() && pattern_chars[pi + 1] == value_chars[vi] {
1676 pi += 1;
1677 vi += 1;
1678 while vi < value_chars.len() && value_chars[vi] == pattern_chars[pi] {
1680 vi += 1;
1681 }
1682 pi += 1;
1683 } else {
1684 return false;
1685 }
1686 } else if let Some(bp) = backtrack_p {
1687 pi = bp + 1;
1688 vi = backtrack_v;
1689 backtrack_v += 1;
1690 } else {
1691 return false;
1692 }
1693 }
1694
1695 while pi < pattern_chars.len() && (pattern_chars[pi] == '*' || pattern_chars[pi] == '+') {
1697 if pattern_chars[pi] == '+' && vi == value_chars.len() {
1698 return false; }
1700 pi += 1;
1701 }
1702
1703 pi == pattern_chars.len()
1704}
1705
1706const fn is_name_start_char(c: char) -> bool {
1708 c.is_ascii_alphabetic()
1709 || c == '_'
1710 || c == ':'
1711 || (c >= '\u{00C0}' && c <= '\u{00D6}')
1712 || (c >= '\u{00D8}' && c <= '\u{00F6}')
1713 || (c >= '\u{00F8}' && c <= '\u{02FF}')
1714 || (c >= '\u{0370}' && c <= '\u{037D}')
1715 || (c >= '\u{037F}' && c <= '\u{1FFF}')
1716 || (c >= '\u{200C}' && c <= '\u{200D}')
1717 || (c >= '\u{2070}' && c <= '\u{218F}')
1718 || (c >= '\u{2C00}' && c <= '\u{2FEF}')
1719 || (c >= '\u{3001}' && c <= '\u{D7FF}')
1720 || (c >= '\u{F900}' && c <= '\u{FDCF}')
1721 || (c >= '\u{FDF0}' && c <= '\u{FFFD}')
1722}
1723
1724const fn is_name_char(c: char) -> bool {
1726 is_name_start_char(c)
1727 || c.is_ascii_digit()
1728 || c == '-'
1729 || c == '.'
1730 || c == '\u{00B7}'
1731 || (c >= '\u{0300}' && c <= '\u{036F}')
1732 || (c >= '\u{203F}' && c <= '\u{2040}')
1733}
1734
1735fn compare_strings(a: &str, b: &str) -> std::cmp::Ordering {
1737 if let (Ok(na), Ok(nb)) = (a.parse::<f64>(), b.parse::<f64>()) {
1739 return na.partial_cmp(&nb).unwrap_or(std::cmp::Ordering::Equal);
1740 }
1741 if let (Ok(na), Ok(nb)) = (a.parse::<i64>(), b.parse::<i64>()) {
1743 return na.cmp(&nb);
1744 }
1745 a.cmp(b)
1747}
1748
1749fn validate_base_type(kind: &XsdDatatypeKind, value: &str) -> bool {
1751 match kind {
1752 XsdDatatypeKind::String => true,
1753 XsdDatatypeKind::NormalizedString => {
1754 !value.contains('\t') && !value.contains('\n') && !value.contains('\r')
1756 }
1757 XsdDatatypeKind::Token => {
1758 if value.is_empty() {
1760 return true;
1761 }
1762 if value.starts_with(' ') || value.ends_with(' ') {
1763 return false;
1764 }
1765 !value.contains(" ")
1766 && !value.contains('\t')
1767 && !value.contains('\n')
1768 && !value.contains('\r')
1769 }
1770 XsdDatatypeKind::Language => {
1771 if value.is_empty() {
1774 return false;
1775 }
1776 let segments: Vec<&str> = value.split('-').collect();
1777 if segments.is_empty() {
1778 return false;
1779 }
1780 if segments[0].is_empty() || !segments[0].chars().all(|c| c.is_ascii_alphabetic()) {
1782 return false;
1783 }
1784 if segments[0].len() > 8 {
1785 return false;
1786 }
1787 for seg in &segments[1..] {
1789 if seg.is_empty() || seg.len() > 8 {
1790 return false;
1791 }
1792 if !seg.chars().all(|c| c.is_ascii_alphanumeric()) {
1793 return false;
1794 }
1795 }
1796 true
1797 }
1798 XsdDatatypeKind::Name => {
1799 if value.is_empty() {
1800 return false;
1801 }
1802 let mut chars = value.chars();
1803 let first = chars.next().unwrap();
1804 if !is_name_start_char(first) {
1805 return false;
1806 }
1807 chars.all(is_name_char)
1808 }
1809 XsdDatatypeKind::NCName
1810 | XsdDatatypeKind::Id
1811 | XsdDatatypeKind::Idref
1812 | XsdDatatypeKind::Entity => {
1813 if value.is_empty() || value.contains(':') {
1815 return false;
1816 }
1817 let mut chars = value.chars();
1818 let first = chars.next().unwrap();
1819 if !is_name_start_char(first) {
1820 return false;
1821 }
1822 chars.all(is_name_char)
1823 }
1824 XsdDatatypeKind::Boolean => {
1825 matches!(value, "true" | "false" | "1" | "0")
1826 }
1827 XsdDatatypeKind::Decimal
1828 | XsdDatatypeKind::Integer
1829 | XsdDatatypeKind::NonPositiveInteger
1830 | XsdDatatypeKind::NegativeInteger
1831 | XsdDatatypeKind::Long
1832 | XsdDatatypeKind::Int
1833 | XsdDatatypeKind::Short
1834 | XsdDatatypeKind::Byte
1835 | XsdDatatypeKind::NonNegativeInteger
1836 | XsdDatatypeKind::UnsignedLong
1837 | XsdDatatypeKind::UnsignedInt
1838 | XsdDatatypeKind::UnsignedShort
1839 | XsdDatatypeKind::UnsignedByte
1840 | XsdDatatypeKind::PositiveInteger => {
1841 if value.is_empty() {
1843 return false;
1844 }
1845 let mut chars = value.chars().peekable();
1846 if *chars.peek().unwrap_or(&'\0') == '-' || *chars.peek().unwrap_or(&'\0') == '+' {
1847 chars.next();
1848 }
1849 let mut has_dot = false;
1850 let mut has_digit = false;
1851 for c in chars {
1852 if c == '.' {
1853 if has_dot {
1854 return false;
1855 }
1856 has_dot = true;
1857 } else if c.is_ascii_digit() {
1858 has_digit = true;
1859 } else {
1860 return false;
1861 }
1862 }
1863 if !has_digit {
1864 return false;
1865 }
1866
1867 if has_dot && *kind != XsdDatatypeKind::Decimal {
1870 return false;
1871 }
1872
1873 match kind {
1874 XsdDatatypeKind::NonPositiveInteger => {
1875 if let Ok(v) = value.parse::<i64>() {
1876 v <= 0
1877 } else {
1878 false
1879 }
1880 }
1881 XsdDatatypeKind::NegativeInteger => {
1882 if let Ok(v) = value.parse::<i64>() {
1883 v < 0
1884 } else {
1885 false
1886 }
1887 }
1888 XsdDatatypeKind::NonNegativeInteger => {
1889 if let Ok(v) = value.parse::<i64>() {
1890 v >= 0
1891 } else {
1892 false
1893 }
1894 }
1895 XsdDatatypeKind::PositiveInteger => {
1896 if let Ok(v) = value.parse::<i64>() {
1897 v > 0
1898 } else {
1899 false
1900 }
1901 }
1902 XsdDatatypeKind::UnsignedLong
1903 | XsdDatatypeKind::UnsignedInt
1904 | XsdDatatypeKind::UnsignedShort
1905 | XsdDatatypeKind::UnsignedByte => {
1906 if let Ok(v) = value.parse::<u64>() {
1907 match kind {
1908 XsdDatatypeKind::UnsignedInt => v <= u64::from(u32::MAX),
1909 XsdDatatypeKind::UnsignedShort => v <= u64::from(u16::MAX),
1910 XsdDatatypeKind::UnsignedByte => v <= u64::from(u8::MAX),
1911 _ => true,
1912 }
1913 } else {
1914 false
1915 }
1916 }
1917 XsdDatatypeKind::Long => value.parse::<i64>().is_ok(),
1918 XsdDatatypeKind::Int => value.parse::<i32>().is_ok(),
1919 XsdDatatypeKind::Short => value.parse::<i16>().is_ok(),
1920 XsdDatatypeKind::Byte => value.parse::<i8>().is_ok(),
1921 _ => true,
1922 }
1923 }
1924 XsdDatatypeKind::Float | XsdDatatypeKind::Double => {
1925 matches!(value, "INF" | "-INF" | "NaN") || value.parse::<f64>().is_ok()
1927 }
1928 XsdDatatypeKind::Duration => {
1929 if !value.starts_with('-') && !value.starts_with('P') {
1931 return false;
1932 }
1933 let dur = value.strip_prefix('-').unwrap_or(value);
1934 if !dur.starts_with('P') {
1935 return false;
1936 }
1937 let rest = &dur[1..];
1938 if rest.is_empty() {
1939 return false;
1940 }
1941 let has_t = rest.contains('T');
1942 let _date_part = if has_t {
1943 &rest[..rest.find('T').unwrap()]
1944 } else {
1945 rest
1946 };
1947 if has_t {
1948 let time_part = &rest[rest.find('T').unwrap() + 1..];
1949 if time_part.is_empty() {
1950 return false;
1951 }
1952 }
1953 true
1954 }
1955 XsdDatatypeKind::DateTime => {
1956 if value.len() < 19 {
1958 return false;
1959 }
1960 let chars: Vec<char> = value.chars().collect();
1961 chars[4] == '-'
1962 && chars[7] == '-'
1963 && chars[10] == 'T'
1964 && chars[13] == ':'
1965 && chars[16] == ':'
1966 }
1967 XsdDatatypeKind::Date => {
1968 if value.len() < 10 {
1970 return false;
1971 }
1972 let chars: Vec<char> = value.chars().collect();
1973 chars[4] == '-' && chars[7] == '-'
1974 }
1975 XsdDatatypeKind::Time => {
1976 if value.len() < 8 {
1978 return false;
1979 }
1980 let chars: Vec<char> = value.chars().collect();
1981 chars[2] == ':' && chars[5] == ':'
1982 }
1983 XsdDatatypeKind::GYear => {
1984 if value.len() < 4 {
1986 return false;
1987 }
1988 value.chars().take(4).all(|c| c.is_ascii_digit())
1989 }
1990 XsdDatatypeKind::GYearMonth => {
1991 if value.len() < 7 {
1993 return false;
1994 }
1995 let chars: Vec<char> = value.chars().collect();
1996 chars[4] == '-'
1997 }
1998 XsdDatatypeKind::GMonthDay => {
1999 if value.len() < 6 || !value.starts_with("--") {
2001 return false;
2002 }
2003 let chars: Vec<char> = value.chars().collect();
2004 chars[4] == '-'
2005 }
2006 XsdDatatypeKind::GDay => {
2007 value.starts_with("---") && value.len() >= 4
2009 }
2010 XsdDatatypeKind::GMonth => {
2011 value.starts_with("--") && value.len() >= 3
2013 }
2014 XsdDatatypeKind::HexBinary => {
2015 if !value.len().is_multiple_of(2) {
2016 return false;
2017 }
2018 value.chars().all(|c| c.is_ascii_hexdigit())
2019 }
2020 XsdDatatypeKind::Base64Binary => {
2021 if value.is_empty() {
2023 return true;
2024 }
2025 let valid_chars =
2026 |c: char| c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=';
2027 value.chars().all(valid_chars)
2028 }
2029 XsdDatatypeKind::AnyURI => {
2030 !value.is_empty()
2032 }
2033 XsdDatatypeKind::QName => {
2034 if let Some(pos) = value.find(':') {
2036 let prefix = &value[..pos];
2037 let local = &value[pos + 1..];
2038 is_ncname(prefix) && is_ncname(local)
2039 } else {
2040 is_ncname(value)
2041 }
2042 }
2043 XsdDatatypeKind::Notation => {
2044 !value.is_empty()
2046 }
2047 XsdDatatypeKind::Nmtoken => !value.is_empty() && value.chars().all(is_name_char),
2048 XsdDatatypeKind::Nmtokens => {
2049 !value.is_empty()
2050 && value
2051 .split_whitespace()
2052 .all(|t| !t.is_empty() && t.chars().all(is_name_char))
2053 }
2054 XsdDatatypeKind::Idrefs | XsdDatatypeKind::Entities => {
2055 !value.is_empty() && value.split_whitespace().all(is_ncname)
2056 }
2057 XsdDatatypeKind::FacetPattern
2059 | XsdDatatypeKind::FacetEnumeration
2060 | XsdDatatypeKind::FacetMinInclusive
2061 | XsdDatatypeKind::FacetMaxInclusive
2062 | XsdDatatypeKind::FacetMinExclusive
2063 | XsdDatatypeKind::FacetMaxExclusive
2064 | XsdDatatypeKind::FacetMinLength
2065 | XsdDatatypeKind::FacetMaxLength
2066 | XsdDatatypeKind::FacetLength
2067 | XsdDatatypeKind::FacetWhiteSpace
2068 | XsdDatatypeKind::FacetFractionDigits
2069 | XsdDatatypeKind::FacetTotalDigits => true,
2070 }
2071}
2072
2073fn is_ncname(value: &str) -> bool {
2075 if value.is_empty() {
2076 return false;
2077 }
2078 let first = value.chars().next().unwrap();
2079 if !is_name_start_char(first) || first == ':' {
2080 return false;
2081 }
2082 value.chars().skip(1).all(|c| is_name_char(c) && c != ':')
2083}
2084
2085pub fn xsd_validate(schema: &XsdSchema, doc: &str) -> Result<(), Vec<String>> {
2102 let doc_ptr = unsafe {
2103 crate::abi::exports_xml2::xmlReadMemory(
2104 doc.as_ptr() as *const c_char,
2105 doc.len() as c_int,
2106 c"doc.xml".as_ptr() as *const c_char,
2107 ptr::null(),
2108 0,
2109 )
2110 };
2111
2112 if doc_ptr.is_null() {
2113 return Err(vec!["Failed to parse XML document".to_string()]);
2114 }
2115
2116 let mut ctxt = XsdValidCtxt::new();
2117 ctxt.schema = Some(schema.clone());
2118
2119 let result = unsafe { xsd_validate_doc(schema, doc_ptr, &mut ctxt) };
2120
2121 unsafe {
2122 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
2123 }
2124
2125 if result {
2126 Ok(())
2127 } else {
2128 Err(ctxt.errors)
2129 }
2130}
2131
2132unsafe fn xsd_validate_doc(schema: &XsdSchema, doc: *mut _xmlDoc, ctxt: &mut XsdValidCtxt) -> bool {
2138 unsafe {
2139 let root = (*doc).children;
2140 if root.is_null() {
2141 ctxt.errors.push("Document has no root element".to_string());
2142 ctxt.nb_errors += 1;
2143 return false;
2144 }
2145
2146 let mut root_elem = root;
2148 while !root_elem.is_null() && (*root_elem).type_ != XML_ELEMENT_NODE as c_int {
2149 root_elem = (*root_elem).next;
2150 }
2151
2152 if root_elem.is_null() {
2153 ctxt.errors.push("Document has no root element".to_string());
2154 ctxt.nb_errors += 1;
2155 return false;
2156 }
2157
2158 let root_name = get_node_qname(root_elem);
2160
2161 let global_elem = schema.components.iter().find(|c| {
2163 c.component_type == XsdComponentType::Element && c.name.as_deref() == Some(&root_name)
2164 });
2165
2166 if let Some(global) = global_elem {
2167 xsd_validate_element(global, root_elem, schema, ctxt)
2168 } else {
2169 let mut valid = true;
2171 for component in &schema.components {
2172 if component.component_type == XsdComponentType::Element {
2173 if let Some(ref name) = component.name {
2174 if *name == root_name {
2175 valid = xsd_validate_element(component, root_elem, schema, ctxt);
2176 break;
2177 }
2178 }
2179 }
2180 }
2181 valid
2182 }
2183 }
2184}
2185
2186fn xsd_validate_element(
2192 component: &XsdComponent,
2193 node: *mut _xmlNode,
2194 schema: &XsdSchema,
2195 ctxt: &mut XsdValidCtxt,
2196) -> bool {
2197 unsafe {
2198 let mut valid = true;
2199
2200 let node_name = get_node_qname(node);
2202
2203 if let Some(ref comp_name) = component.name {
2205 if comp_name != &node_name {
2206 ctxt.errors.push(format!(
2207 "Element '{}' does not match expected '{}'",
2208 node_name, comp_name
2209 ));
2210 ctxt.nb_errors += 1;
2211 return false;
2212 }
2213 }
2214
2215 let type_comp = component.children.iter().find(|c| {
2217 c.component_type == XsdComponentType::ComplexType
2218 || c.component_type == XsdComponentType::SimpleType
2219 });
2220
2221 if let Some(tc) = type_comp {
2222 match tc.component_type {
2223 XsdComponentType::ComplexType => {
2224 valid &= xsd_validate_complex_type(tc, node, schema, ctxt);
2225 }
2226 XsdComponentType::SimpleType => {
2227 let text = get_node_text(node);
2228 if let Some(ref dt) = tc.datatype {
2229 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2230 ctxt.errors.push(format!(
2231 "Element '{}' has invalid value '{}' for type '{:?}'",
2232 node_name, text, dt
2233 ));
2234 ctxt.nb_errors += 1;
2235 valid = false;
2236 }
2237 }
2238 }
2239 _ => {}
2240 }
2241 } else if let Some(ref dt) = component.datatype {
2242 let text = get_node_text(node);
2244 if !xsd_validate_datatype(dt, &text, &component.facets) {
2245 ctxt.errors.push(format!(
2246 "Element '{}' has invalid value '{}' for type '{:?}'",
2247 node_name, text, dt
2248 ));
2249 ctxt.nb_errors += 1;
2250 valid = false;
2251 }
2252 } else {
2253 valid &= xsd_validate_content(component, node, schema, ctxt);
2255 }
2256
2257 valid
2258 }
2259}
2260
2261fn xsd_validate_complex_type(
2267 component: &XsdComponent,
2268 node: *mut _xmlNode,
2269 schema: &XsdSchema,
2270 ctxt: &mut XsdValidCtxt,
2271) -> bool {
2272 {
2273 let mut valid = true;
2274
2275 for attr in &component.attributes {
2277 match attr.component_type {
2278 XsdComponentType::Attribute => {
2279 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2280 }
2281 XsdComponentType::AnyAttribute => {
2282 }
2284 _ => {}
2285 }
2286 }
2287
2288 for child in &component.children {
2290 match child.component_type {
2291 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2292 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2293 }
2294 XsdComponentType::Restriction | XsdComponentType::Extension => {
2295 valid &= xsd_validate_restriction_extension(child, node, schema, ctxt);
2297 }
2298 XsdComponentType::Any => {
2299 }
2301 _ => {}
2302 }
2303 }
2304
2305 valid
2306 }
2307}
2308
2309fn xsd_validate_model_group(
2315 component: &XsdComponent,
2316 node: *mut _xmlNode,
2317 _schema: &XsdSchema,
2318 ctxt: &mut XsdValidCtxt,
2319) -> bool {
2320 unsafe {
2321 let mut valid = true;
2322
2323 let mut child_nodes: Vec<*mut _xmlNode> = Vec::new();
2325 let mut child = (*node).children;
2326 while !child.is_null() {
2327 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2328 child_nodes.push(child);
2329 }
2330 child = (*child).next;
2331 }
2332
2333 match component.component_type {
2334 XsdComponentType::Sequence => {
2335 let mut child_idx = 0;
2337 for part in &component.children {
2338 let min = part.min_occurs;
2339 let max = part.max_occurs;
2340 let match_name = part.name.as_deref().unwrap_or("");
2341 let match_ref = part.ref_name.as_deref().unwrap_or("");
2342
2343 let mut count = 0;
2344 while child_idx < child_nodes.len() && (max == -1 || count < max) {
2345 let child_node = child_nodes[child_idx];
2346 let child_name = get_node_qname(child_node);
2347
2348 if part.component_type == XsdComponentType::Any
2349 || (!match_name.is_empty() && child_name == match_name)
2350 || (!match_ref.is_empty() && child_name == match_ref)
2351 {
2352 count += 1;
2353 child_idx += 1;
2354 } else if count >= min {
2355 break;
2356 } else {
2357 ctxt.errors.push(format!(
2358 "Expected element '{}' but found '{}'",
2359 match_name, child_name
2360 ));
2361 ctxt.nb_errors += 1;
2362 valid = false;
2363 child_idx += 1;
2364 break;
2365 }
2366 }
2367
2368 if count < min {
2369 ctxt.errors.push(format!(
2370 "Element '{}' occurs {} times, minimum is {}",
2371 if match_name.is_empty() {
2372 "?"
2373 } else {
2374 match_name
2375 },
2376 count,
2377 min
2378 ));
2379 ctxt.nb_errors += 1;
2380 valid = false;
2381 }
2382 }
2383
2384 if child_idx < child_nodes.len() {
2386 let extra = get_node_qname(child_nodes[child_idx]);
2387 ctxt.errors
2388 .push(format!("Unexpected element '{}' in sequence", extra));
2389 ctxt.nb_errors += 1;
2390 valid = false;
2391 }
2392 }
2393 XsdComponentType::Choice => {
2394 let mut matched = false;
2396 for child_node in &child_nodes {
2397 let child_name = get_node_qname(*child_node);
2398 for part in &component.children {
2399 let match_name = part.name.as_deref().unwrap_or("");
2400 let match_ref = part.ref_name.as_deref().unwrap_or("");
2401
2402 if part.component_type == XsdComponentType::Any {
2403 matched = true;
2404 } else if (!match_name.is_empty() && child_name == match_name)
2405 || (!match_ref.is_empty() && child_name == match_ref)
2406 {
2407 matched = true;
2408 break;
2409 }
2410 }
2411 if !matched {
2412 ctxt.errors
2413 .push(format!("Element '{}' is not valid in choice", child_name));
2414 ctxt.nb_errors += 1;
2415 valid = false;
2416 }
2417 matched = false; }
2419 }
2420 XsdComponentType::All => {
2421 for child_node in &child_nodes {
2423 let child_name = get_node_qname(*child_node);
2424 let mut matched = false;
2425 for part in &component.children {
2426 let match_name = part.name.as_deref().unwrap_or("");
2427 if !match_name.is_empty() && child_name == match_name {
2428 matched = true;
2429 break;
2430 }
2431 }
2432 if !matched {
2433 ctxt.errors.push(format!(
2434 "Element '{}' is not valid in all group",
2435 child_name
2436 ));
2437 ctxt.nb_errors += 1;
2438 valid = false;
2439 }
2440 }
2441 }
2442 _ => {}
2443 }
2444
2445 valid
2446 }
2447}
2448
2449fn xsd_validate_restriction_extension(
2455 component: &XsdComponent,
2456 node: *mut _xmlNode,
2457 schema: &XsdSchema,
2458 ctxt: &mut XsdValidCtxt,
2459) -> bool {
2460 unsafe {
2461 let mut valid = true;
2462
2463 for attr in &component.attributes {
2465 if attr.component_type == XsdComponentType::Attribute {
2466 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2467 }
2468 }
2469
2470 for child in &component.children {
2472 match child.component_type {
2473 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2474 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2475 }
2476 _ => {}
2477 }
2478 }
2479
2480 if let Some(ref dt) = component.datatype {
2482 let text = get_node_text(node);
2483 if !xsd_validate_datatype(dt, &text, &component.facets) {
2484 let node_name = get_node_qname(node);
2485 ctxt.errors.push(format!(
2486 "Element '{}' has invalid value '{}' for type '{:?}'",
2487 node_name, text, dt
2488 ));
2489 ctxt.nb_errors += 1;
2490 valid = false;
2491 }
2492 }
2493
2494 valid
2495 }
2496}
2497
2498fn xsd_validate_attribute(
2504 component: &XsdComponent,
2505 node: *mut _xmlNode,
2506 _schema: &XsdSchema,
2507 ctxt: &mut XsdValidCtxt,
2508) -> bool {
2509 unsafe {
2510 let attr_name = component.name.as_deref().unwrap_or("");
2511 if attr_name.is_empty() {
2512 return true;
2513 }
2514
2515 let attr_value = get_attr(node, attr_name);
2517
2518 let is_required = component.min_occurs > 0;
2519
2520 match attr_value {
2521 Some(ref val) => {
2522 if let Some(ref dt) = component.datatype {
2524 if !xsd_validate_datatype(dt, val, &component.facets) {
2525 ctxt.errors.push(format!(
2526 "Attribute '{}' has invalid value '{}' for type '{:?}'",
2527 attr_name, val, dt
2528 ));
2529 ctxt.nb_errors += 1;
2530 return false;
2531 }
2532 }
2533 true
2534 }
2535 None => {
2536 if is_required {
2537 ctxt.errors
2538 .push(format!("Required attribute '{}' is missing", attr_name));
2539 ctxt.nb_errors += 1;
2540 false
2541 } else {
2542 true
2543 }
2544 }
2545 }
2546 }
2547}
2548
2549fn xsd_validate_content(
2555 component: &XsdComponent,
2556 node: *mut _xmlNode,
2557 schema: &XsdSchema,
2558 ctxt: &mut XsdValidCtxt,
2559) -> bool {
2560 {
2561 let mut valid = true;
2562
2563 for child_comp in &component.children {
2564 match child_comp.component_type {
2565 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2566 valid &= xsd_validate_model_group(child_comp, node, schema, ctxt);
2567 }
2568 XsdComponentType::Element => {
2569 valid &= xsd_validate_element_inline(child_comp, node, schema, ctxt);
2571 }
2572 _ => {}
2573 }
2574 }
2575
2576 valid
2577 }
2578}
2579
2580fn xsd_validate_element_inline(
2586 component: &XsdComponent,
2587 node: *mut _xmlNode,
2588 schema: &XsdSchema,
2589 ctxt: &mut XsdValidCtxt,
2590) -> bool {
2591 unsafe {
2592 let mut valid = true;
2593 let mut child = (*node).children;
2594
2595 while !child.is_null() {
2596 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2597 let child_name = get_node_qname(child);
2598
2599 let match_name = component.name.as_deref().unwrap_or("");
2600 let match_ref = component.ref_name.as_deref().unwrap_or("");
2601
2602 if (!match_name.is_empty() && child_name == match_name)
2603 || (!match_ref.is_empty() && child_name == match_ref)
2604 {
2605 let type_comp = component.children.iter().find(|c| {
2607 c.component_type == XsdComponentType::ComplexType
2608 || c.component_type == XsdComponentType::SimpleType
2609 });
2610
2611 if let Some(tc) = type_comp {
2612 match tc.component_type {
2613 XsdComponentType::ComplexType => {
2614 valid &= xsd_validate_complex_type(tc, child, schema, ctxt);
2615 }
2616 XsdComponentType::SimpleType => {
2617 let text = get_node_text(child);
2618 if let Some(ref dt) = tc.datatype {
2619 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2620 ctxt.errors.push(format!(
2621 "Element '{}' has invalid value '{}'",
2622 child_name, text
2623 ));
2624 ctxt.nb_errors += 1;
2625 valid = false;
2626 }
2627 }
2628 }
2629 _ => {}
2630 }
2631 }
2632 }
2633 }
2634 child = (*child).next;
2635 }
2636
2637 valid
2638 }
2639}
2640
2641unsafe fn get_node_qname(node: *mut _xmlNode) -> String {
2647 if node.is_null() {
2648 return String::new();
2649 }
2650 unsafe {
2651 let ns = (*node).ns;
2653 let prefix = if !ns.is_null() && !(*ns).prefix.is_null() {
2654 let mut len = 0;
2655 while *(*ns).prefix.add(len) != 0 {
2656 len += 1;
2657 }
2658 let slice = std::slice::from_raw_parts((*ns).prefix, len);
2659 if let Ok(s) = std::str::from_utf8(slice) {
2660 format!("{}:", s)
2661 } else {
2662 String::new()
2663 }
2664 } else {
2665 String::new()
2666 };
2667
2668 let name = (*node).name;
2669 if name.is_null() {
2670 return String::new();
2671 }
2672 let mut len = 0;
2673 while *name.add(len) != 0 {
2674 len += 1;
2675 }
2676 let slice = std::slice::from_raw_parts(name, len);
2677 if let Ok(s) = std::str::from_utf8(slice) {
2678 format!("{}{}", prefix, s)
2679 } else {
2680 String::new()
2681 }
2682 }
2683}
2684
2685#[no_mangle]
2704pub unsafe extern "C" fn xmlSchemaNewParserCtxt(url: *const c_char) -> *mut c_void {
2705 if url.is_null() {
2706 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2708 return ctxt;
2709 }
2710
2711 let url_str = unsafe {
2713 if url.is_null() {
2714 String::new()
2715 } else {
2716 let mut len = 0;
2717 while *url.add(len) != 0 {
2718 len += 1;
2719 }
2720 let slice = std::slice::from_raw_parts(url as *const u8, len);
2721 String::from_utf8_lossy(slice).to_string()
2722 }
2723 };
2724
2725 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2728 if !url_str.is_empty() {
2730 let _ = url_str;
2732 }
2733
2734 ctxt
2735}
2736
2737#[no_mangle]
2749pub unsafe extern "C" fn xmlSchemaNewMemParserCtxt(
2750 buffer: *const c_char,
2751 size: c_int,
2752) -> *mut c_void {
2753 if buffer.is_null() || size <= 0 {
2754 return ptr::null_mut();
2755 }
2756
2757 let buf_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, size as usize) };
2759 let xml_str = String::from_utf8_lossy(buf_slice).to_string();
2760
2761 match xsd_parse(&xml_str) {
2762 Ok(schema) => {
2763 let schema_box = Box::new(schema);
2765 Box::into_raw(schema_box) as *mut c_void
2766 }
2767 Err(_) => ptr::null_mut(),
2768 }
2769}
2770
2771#[no_mangle]
2783pub const unsafe extern "C" fn xmlSchemaParse(ctxt: *mut c_void) -> *mut c_void {
2784 if ctxt.is_null() {
2785 return ptr::null_mut();
2786 }
2787
2788 ctxt
2792}
2793
2794#[no_mangle]
2806pub unsafe extern "C" fn xmlSchemaFree(schema: *mut c_void) {
2807 if schema.is_null() {
2808 return;
2809 }
2810 unsafe {
2812 let _ = Box::from_raw(schema as *mut XsdSchema);
2813 }
2814}
2815
2816#[no_mangle]
2831pub unsafe extern "C" fn xmlSchemaValidateDoc(ctxt: *mut c_void, doc: *mut _xmlDoc) -> c_int {
2832 if ctxt.is_null() || doc.is_null() {
2833 return -1;
2834 }
2835
2836 unsafe {
2837 let valid_ctxt = &mut *(ctxt as *mut XsdValidCtxt);
2838 let schema = match &valid_ctxt.schema {
2839 Some(s) => s,
2840 None => return -1,
2841 };
2842
2843 let mut temp_ctxt = XsdValidCtxt::new();
2844 temp_ctxt.schema = Some(schema.clone());
2845
2846 let valid = xsd_validate_doc(schema, doc, &mut temp_ctxt);
2847
2848 if valid {
2849 0
2850 } else {
2851 valid_ctxt.errors = temp_ctxt.errors;
2852 valid_ctxt.nb_errors = temp_ctxt.nb_errors;
2853 temp_ctxt.nb_errors
2854 }
2855 }
2856}
2857
2858#[no_mangle]
2870pub unsafe extern "C" fn xmlSchemaFreeParserCtxt(ctxt: *mut c_void) {
2871 if ctxt.is_null() {
2872 return;
2873 }
2874 unsafe {
2876 let _ = Box::from_raw(ctxt as *mut XsdSchema);
2877 }
2878}
2879
2880#[no_mangle]
2892pub unsafe extern "C" fn xmlSchemaFreeValidCtxt(ctxt: *mut c_void) {
2893 if ctxt.is_null() {
2894 return;
2895 }
2896 unsafe {
2898 let _ = Box::from_raw(ctxt as *mut XsdValidCtxt);
2899 }
2900}
2901
2902#[no_mangle]
2914pub unsafe extern "C" fn xmlSchemaNewValidCtxt(schema: *mut c_void) -> *mut c_void {
2915 let mut ctxt = XsdValidCtxt::new();
2916
2917 if !schema.is_null() {
2918 unsafe {
2920 let schema_ref = &*(schema as *const XsdSchema);
2921 ctxt.schema = Some(schema_ref.clone());
2922 }
2923 }
2924
2925 let boxed = Box::new(ctxt);
2926 Box::into_raw(boxed) as *mut c_void
2927}
2928
2929#[cfg(test)]
2934mod tests {
2935 use super::*;
2936
2937 #[test]
2940 fn test_validate_string() {
2941 assert!(xsd_validate_datatype(
2942 &XsdDatatypeKind::String,
2943 "hello",
2944 &[]
2945 ));
2946 assert!(xsd_validate_datatype(&XsdDatatypeKind::String, "", &[]));
2947 }
2948
2949 #[test]
2950 fn test_validate_boolean() {
2951 assert!(xsd_validate_datatype(
2952 &XsdDatatypeKind::Boolean,
2953 "true",
2954 &[]
2955 ));
2956 assert!(xsd_validate_datatype(
2957 &XsdDatatypeKind::Boolean,
2958 "false",
2959 &[]
2960 ));
2961 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "1", &[]));
2962 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "0", &[]));
2963 assert!(!xsd_validate_datatype(
2964 &XsdDatatypeKind::Boolean,
2965 "yes",
2966 &[]
2967 ));
2968 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Boolean, "no", &[]));
2969 }
2970
2971 #[test]
2972 fn test_validate_integer() {
2973 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "42", &[]));
2974 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "-42", &[]));
2975 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "+42", &[]));
2976 assert!(!xsd_validate_datatype(
2977 &XsdDatatypeKind::Integer,
2978 "12.5",
2979 &[]
2980 ));
2981 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Integer, "", &[]));
2982 assert!(!xsd_validate_datatype(
2983 &XsdDatatypeKind::Integer,
2984 "abc",
2985 &[]
2986 ));
2987 }
2988
2989 #[test]
2990 fn test_validate_decimal() {
2991 assert!(xsd_validate_datatype(&XsdDatatypeKind::Decimal, "42", &[]));
2992 assert!(xsd_validate_datatype(
2993 &XsdDatatypeKind::Decimal,
2994 "12.5",
2995 &[]
2996 ));
2997 assert!(xsd_validate_datatype(
2998 &XsdDatatypeKind::Decimal,
2999 "-3.14",
3000 &[]
3001 ));
3002 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Decimal, "", &[]));
3003 }
3004
3005 #[test]
3006 fn test_validate_float() {
3007 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "3.14", &[]));
3008 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "INF", &[]));
3009 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "-INF", &[]));
3010 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "NaN", &[]));
3011 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Float, "", &[]));
3012 }
3013
3014 #[test]
3015 fn test_validate_positive_integer() {
3016 assert!(xsd_validate_datatype(
3017 &XsdDatatypeKind::PositiveInteger,
3018 "1",
3019 &[]
3020 ));
3021 assert!(xsd_validate_datatype(
3022 &XsdDatatypeKind::PositiveInteger,
3023 "100",
3024 &[]
3025 ));
3026 assert!(!xsd_validate_datatype(
3027 &XsdDatatypeKind::PositiveInteger,
3028 "0",
3029 &[]
3030 ));
3031 assert!(!xsd_validate_datatype(
3032 &XsdDatatypeKind::PositiveInteger,
3033 "-1",
3034 &[]
3035 ));
3036 }
3037
3038 #[test]
3039 fn test_validate_non_negative_integer() {
3040 assert!(xsd_validate_datatype(
3041 &XsdDatatypeKind::NonNegativeInteger,
3042 "0",
3043 &[]
3044 ));
3045 assert!(xsd_validate_datatype(
3046 &XsdDatatypeKind::NonNegativeInteger,
3047 "42",
3048 &[]
3049 ));
3050 assert!(!xsd_validate_datatype(
3051 &XsdDatatypeKind::NonNegativeInteger,
3052 "-1",
3053 &[]
3054 ));
3055 }
3056
3057 #[test]
3058 fn test_validate_int_range() {
3059 assert!(xsd_validate_datatype(
3060 &XsdDatatypeKind::Int,
3061 "2147483647",
3062 &[]
3063 ));
3064 assert!(xsd_validate_datatype(
3065 &XsdDatatypeKind::Int,
3066 "-2147483648",
3067 &[]
3068 ));
3069 assert!(!xsd_validate_datatype(
3070 &XsdDatatypeKind::Int,
3071 "2147483648",
3072 &[]
3073 ));
3074 }
3075
3076 #[test]
3077 fn test_validate_short_range() {
3078 assert!(xsd_validate_datatype(&XsdDatatypeKind::Short, "32767", &[]));
3079 assert!(xsd_validate_datatype(
3080 &XsdDatatypeKind::Short,
3081 "-32768",
3082 &[]
3083 ));
3084 assert!(!xsd_validate_datatype(
3085 &XsdDatatypeKind::Short,
3086 "32768",
3087 &[]
3088 ));
3089 }
3090
3091 #[test]
3092 fn test_validate_byte_range() {
3093 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "127", &[]));
3094 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "-128", &[]));
3095 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Byte, "128", &[]));
3096 }
3097
3098 #[test]
3099 fn test_validate_date_time() {
3100 assert!(xsd_validate_datatype(
3101 &XsdDatatypeKind::DateTime,
3102 "2023-01-15T10:30:00",
3103 &[]
3104 ));
3105 assert!(!xsd_validate_datatype(
3106 &XsdDatatypeKind::DateTime,
3107 "not-a-date",
3108 &[]
3109 ));
3110 }
3111
3112 #[test]
3113 fn test_validate_date() {
3114 assert!(xsd_validate_datatype(
3115 &XsdDatatypeKind::Date,
3116 "2023-01-15",
3117 &[]
3118 ));
3119 assert!(!xsd_validate_datatype(
3120 &XsdDatatypeKind::Date,
3121 "2023/01/15",
3122 &[]
3123 ));
3124 }
3125
3126 #[test]
3127 fn test_validate_time() {
3128 assert!(xsd_validate_datatype(
3129 &XsdDatatypeKind::Time,
3130 "10:30:00",
3131 &[]
3132 ));
3133 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Time, "10:30", &[]));
3134 }
3135
3136 #[test]
3137 fn test_validate_hex_binary() {
3138 assert!(xsd_validate_datatype(
3139 &XsdDatatypeKind::HexBinary,
3140 "0FA1",
3141 &[]
3142 ));
3143 assert!(xsd_validate_datatype(&XsdDatatypeKind::HexBinary, "", &[]));
3144 assert!(!xsd_validate_datatype(
3145 &XsdDatatypeKind::HexBinary,
3146 "0FG1",
3147 &[]
3148 ));
3149 assert!(!xsd_validate_datatype(
3150 &XsdDatatypeKind::HexBinary,
3151 "0FA",
3152 &[]
3153 ));
3154 }
3155
3156 #[test]
3157 fn test_validate_base64() {
3158 assert!(xsd_validate_datatype(
3159 &XsdDatatypeKind::Base64Binary,
3160 "SGVsbG8=",
3161 &[]
3162 ));
3163 assert!(xsd_validate_datatype(
3164 &XsdDatatypeKind::Base64Binary,
3165 "",
3166 &[]
3167 ));
3168 assert!(!xsd_validate_datatype(
3169 &XsdDatatypeKind::Base64Binary,
3170 "Hello World!",
3171 &[]
3172 ));
3173 }
3174
3175 #[test]
3176 fn test_validate_ncname() {
3177 assert!(xsd_validate_datatype(
3178 &XsdDatatypeKind::NCName,
3179 "myElement",
3180 &[]
3181 ));
3182 assert!(xsd_validate_datatype(&XsdDatatypeKind::NCName, "_foo", &[]));
3183 assert!(!xsd_validate_datatype(
3184 &XsdDatatypeKind::NCName,
3185 "123abc",
3186 &[]
3187 ));
3188 assert!(!xsd_validate_datatype(&XsdDatatypeKind::NCName, "", &[]));
3189 }
3190
3191 #[test]
3192 fn test_validate_qname() {
3193 assert!(xsd_validate_datatype(
3194 &XsdDatatypeKind::QName,
3195 "ns:local",
3196 &[]
3197 ));
3198 assert!(xsd_validate_datatype(&XsdDatatypeKind::QName, "local", &[]));
3199 assert!(!xsd_validate_datatype(&XsdDatatypeKind::QName, "", &[]));
3200 }
3201
3202 #[test]
3203 fn test_validate_token() {
3204 assert!(xsd_validate_datatype(&XsdDatatypeKind::Token, "hello", &[]));
3205 assert!(!xsd_validate_datatype(
3206 &XsdDatatypeKind::Token,
3207 " hello",
3208 &[]
3209 ));
3210 assert!(!xsd_validate_datatype(
3211 &XsdDatatypeKind::Token,
3212 "hello ",
3213 &[]
3214 ));
3215 assert!(!xsd_validate_datatype(
3216 &XsdDatatypeKind::Token,
3217 "hello world",
3218 &[]
3219 ));
3220 assert!(!xsd_validate_datatype(
3221 &XsdDatatypeKind::Token,
3222 "hello\tworld",
3223 &[]
3224 ));
3225 }
3226
3227 #[test]
3228 fn test_validate_language() {
3229 assert!(xsd_validate_datatype(&XsdDatatypeKind::Language, "en", &[]));
3230 assert!(xsd_validate_datatype(
3231 &XsdDatatypeKind::Language,
3232 "en-US",
3233 &[]
3234 ));
3235 assert!(xsd_validate_datatype(
3236 &XsdDatatypeKind::Language,
3237 "zh-CN",
3238 &[]
3239 ));
3240 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Language, "", &[]));
3241 assert!(!xsd_validate_datatype(
3242 &XsdDatatypeKind::Language,
3243 "123",
3244 &[]
3245 ));
3246 }
3247
3248 #[test]
3249 fn test_validate_name() {
3250 assert!(xsd_validate_datatype(
3251 &XsdDatatypeKind::Name,
3252 "myElement",
3253 &[]
3254 ));
3255 assert!(xsd_validate_datatype(
3256 &XsdDatatypeKind::Name,
3257 "ns:local",
3258 &[]
3259 ));
3260 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Name, "", &[]));
3261 }
3262
3263 #[test]
3264 fn test_validate_nmtoken() {
3265 assert!(xsd_validate_datatype(
3266 &XsdDatatypeKind::Nmtoken,
3267 "token123",
3268 &[]
3269 ));
3270 assert!(xsd_validate_datatype(
3271 &XsdDatatypeKind::Nmtoken,
3272 "123token",
3273 &[]
3274 ));
3275 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Nmtoken, "", &[]));
3276 }
3277
3278 #[test]
3279 fn test_validate_duration() {
3280 assert!(xsd_validate_datatype(
3281 &XsdDatatypeKind::Duration,
3282 "P1Y2M3DT4H5M6S",
3283 &[]
3284 ));
3285 assert!(xsd_validate_datatype(
3286 &XsdDatatypeKind::Duration,
3287 "P1Y",
3288 &[]
3289 ));
3290 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Duration, "", &[]));
3291 }
3292
3293 #[test]
3294 fn test_validate_g_year() {
3295 assert!(xsd_validate_datatype(&XsdDatatypeKind::GYear, "2023", &[]));
3296 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GYear, "", &[]));
3297 }
3298
3299 #[test]
3300 fn test_validate_g_month() {
3301 assert!(xsd_validate_datatype(&XsdDatatypeKind::GMonth, "--05", &[]));
3302 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GMonth, "", &[]));
3303 }
3304
3305 #[test]
3306 fn test_validate_g_day() {
3307 assert!(xsd_validate_datatype(&XsdDatatypeKind::GDay, "---15", &[]));
3308 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GDay, "", &[]));
3309 }
3310
3311 #[test]
3314 fn test_facet_min_length() {
3315 let facets = vec![(XsdDatatypeKind::FacetMinLength, "3".to_string())];
3316 assert!(xsd_validate_datatype(
3317 &XsdDatatypeKind::String,
3318 "hello",
3319 &facets
3320 ));
3321 assert!(xsd_validate_datatype(
3322 &XsdDatatypeKind::String,
3323 "abc",
3324 &facets
3325 ));
3326 assert!(!xsd_validate_datatype(
3327 &XsdDatatypeKind::String,
3328 "ab",
3329 &facets
3330 ));
3331 }
3332
3333 #[test]
3334 fn test_facet_max_length() {
3335 let facets = vec![(XsdDatatypeKind::FacetMaxLength, "3".to_string())];
3336 assert!(xsd_validate_datatype(
3337 &XsdDatatypeKind::String,
3338 "ab",
3339 &facets
3340 ));
3341 assert!(xsd_validate_datatype(
3342 &XsdDatatypeKind::String,
3343 "abc",
3344 &facets
3345 ));
3346 assert!(!xsd_validate_datatype(
3347 &XsdDatatypeKind::String,
3348 "abcd",
3349 &facets
3350 ));
3351 }
3352
3353 #[test]
3354 fn test_facet_length() {
3355 let facets = vec![(XsdDatatypeKind::FacetLength, "3".to_string())];
3356 assert!(xsd_validate_datatype(
3357 &XsdDatatypeKind::String,
3358 "abc",
3359 &facets
3360 ));
3361 assert!(!xsd_validate_datatype(
3362 &XsdDatatypeKind::String,
3363 "ab",
3364 &facets
3365 ));
3366 assert!(!xsd_validate_datatype(
3367 &XsdDatatypeKind::String,
3368 "abcd",
3369 &facets
3370 ));
3371 }
3372
3373 #[test]
3374 fn test_facet_min_inclusive() {
3375 let facets = vec![(XsdDatatypeKind::FacetMinInclusive, "5".to_string())];
3376 assert!(xsd_validate_datatype(
3377 &XsdDatatypeKind::Integer,
3378 "5",
3379 &facets
3380 ));
3381 assert!(xsd_validate_datatype(
3382 &XsdDatatypeKind::Integer,
3383 "10",
3384 &facets
3385 ));
3386 assert!(!xsd_validate_datatype(
3387 &XsdDatatypeKind::Integer,
3388 "3",
3389 &facets
3390 ));
3391 }
3392
3393 #[test]
3394 fn test_facet_max_inclusive() {
3395 let facets = vec![(XsdDatatypeKind::FacetMaxInclusive, "10".to_string())];
3396 assert!(xsd_validate_datatype(
3397 &XsdDatatypeKind::Integer,
3398 "10",
3399 &facets
3400 ));
3401 assert!(xsd_validate_datatype(
3402 &XsdDatatypeKind::Integer,
3403 "5",
3404 &facets
3405 ));
3406 assert!(!xsd_validate_datatype(
3407 &XsdDatatypeKind::Integer,
3408 "15",
3409 &facets
3410 ));
3411 }
3412
3413 #[test]
3414 fn test_facet_pattern_digits() {
3415 let facets = vec![(XsdDatatypeKind::FacetPattern, r"\d+".to_string())];
3416 assert!(xsd_validate_datatype(
3417 &XsdDatatypeKind::String,
3418 "123",
3419 &facets
3420 ));
3421 assert!(!xsd_validate_datatype(
3422 &XsdDatatypeKind::String,
3423 "abc",
3424 &facets
3425 ));
3426 }
3427
3428 #[test]
3429 fn test_facet_pattern_alpha() {
3430 let facets = vec![(XsdDatatypeKind::FacetPattern, r"[a-zA-Z]+".to_string())];
3431 assert!(xsd_validate_datatype(
3432 &XsdDatatypeKind::String,
3433 "hello",
3434 &facets
3435 ));
3436 assert!(!xsd_validate_datatype(
3437 &XsdDatatypeKind::String,
3438 "123",
3439 &facets
3440 ));
3441 }
3442
3443 #[test]
3446 fn test_parse_empty_schema() {
3447 let schema_xml = r#"<?xml version="1.0"?>
3448 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3449 </xs:schema>"#;
3450
3451 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3452 assert!(schema.components.is_empty());
3453 }
3454
3455 #[test]
3456 fn test_parse_schema_with_target_namespace() {
3457 let schema_xml = r#"<?xml version="1.0"?>
3458 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
3459 targetNamespace="http://example.com/ns">
3460 </xs:schema>"#;
3461
3462 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3463 assert_eq!(
3464 schema.target_namespace,
3465 Some("http://example.com/ns".to_string())
3466 );
3467 }
3468
3469 #[test]
3470 fn test_parse_simple_element() {
3471 let schema_xml = r#"<?xml version="1.0"?>
3472 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3473 <xs:element name="name" type="xs:string"/>
3474 </xs:schema>"#;
3475
3476 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3477 assert_eq!(schema.components.len(), 1);
3478 assert_eq!(
3479 schema.components[0].component_type,
3480 XsdComponentType::Element
3481 );
3482 assert_eq!(schema.components[0].name, Some("name".to_string()));
3483 assert_eq!(schema.components[0].datatype, Some(XsdDatatypeKind::String));
3484 }
3485
3486 #[test]
3487 fn test_parse_integer_element() {
3488 let schema_xml = r#"<?xml version="1.0"?>
3489 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3490 <xs:element name="age" type="xs:integer"/>
3491 </xs:schema>"#;
3492
3493 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3494 assert_eq!(schema.components.len(), 1);
3495 assert_eq!(schema.components[0].name, Some("age".to_string()));
3496 assert_eq!(
3497 schema.components[0].datatype,
3498 Some(XsdDatatypeKind::Integer)
3499 );
3500 }
3501
3502 #[test]
3503 fn test_parse_element_with_attributes() {
3504 let schema_xml = r#"<?xml version="1.0"?>
3505 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3506 <xs:element name="product">
3507 <xs:complexType>
3508 <xs:sequence>
3509 <xs:element name="name" type="xs:string"/>
3510 <xs:element name="price" type="xs:decimal"/>
3511 </xs:sequence>
3512 <xs:attribute name="id" type="xs:integer" use="required"/>
3513 </xs:complexType>
3514 </xs:element>
3515 </xs:schema>"#;
3516
3517 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3518 assert_eq!(schema.components.len(), 1);
3519 assert_eq!(schema.components[0].name, Some("product".to_string()));
3520
3521 let ct = &schema.components[0].children;
3523 let complex_type = ct
3524 .iter()
3525 .find(|c| c.component_type == XsdComponentType::ComplexType);
3526 assert!(complex_type.is_some());
3527 if let Some(ctc) = complex_type {
3528 assert_eq!(ctc.attributes.len(), 1);
3529 assert_eq!(ctc.attributes[0].name, Some("id".to_string()));
3530 assert_eq!(ctc.attributes[0].datatype, Some(XsdDatatypeKind::Integer));
3531 }
3532 }
3533
3534 #[test]
3535 fn test_parse_complex_type_with_sequence() {
3536 let schema_xml = r#"<?xml version="1.0"?>
3537 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3538 <xs:complexType name="AddressType">
3539 <xs:sequence>
3540 <xs:element name="street" type="xs:string"/>
3541 <xs:element name="city" type="xs:string"/>
3542 <xs:element name="zip" type="xs:string"/>
3543 </xs:sequence>
3544 </xs:complexType>
3545 </xs:schema>"#;
3546
3547 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3548 assert_eq!(schema.components.len(), 1);
3549 assert_eq!(
3550 schema.components[0].component_type,
3551 XsdComponentType::ComplexType
3552 );
3553 assert_eq!(schema.components[0].name, Some("AddressType".to_string()));
3554 }
3555
3556 #[test]
3557 fn test_parse_restriction() {
3558 let schema_xml = r#"<?xml version="1.0"?>
3559 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3560 <xs:simpleType name="AgeType">
3561 <xs:restriction base="xs:integer">
3562 <xs:minInclusive value="0"/>
3563 <xs:maxInclusive value="150"/>
3564 </xs:restriction>
3565 </xs:simpleType>
3566 </xs:schema>"#;
3567
3568 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3569 assert_eq!(schema.components.len(), 1);
3570 assert_eq!(
3571 schema.components[0].component_type,
3572 XsdComponentType::SimpleType
3573 );
3574
3575 let st = &schema.components[0];
3577 assert_eq!(st.datatype, Some(XsdDatatypeKind::Integer));
3578 assert!(!st.facets.is_empty());
3579 }
3580
3581 #[test]
3582 fn test_parse_enumeration() {
3583 let schema_xml = r#"<?xml version="1.0"?>
3584 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3585 <xs:simpleType name="ColorType">
3586 <xs:restriction base="xs:string">
3587 <xs:enumeration value="red"/>
3588 <xs:enumeration value="green"/>
3589 <xs:enumeration value="blue"/>
3590 </xs:restriction>
3591 </xs:simpleType>
3592 </xs:schema>"#;
3593
3594 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3595 assert_eq!(schema.components.len(), 1);
3596 assert_eq!(schema.components[0].name, Some("ColorType".to_string()));
3597 }
3598
3599 #[test]
3600 fn test_parse_min_max_occurs() {
3601 let schema_xml = r#"<?xml version="1.0"?>
3602 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3603 <xs:element name="items">
3604 <xs:complexType>
3605 <xs:sequence>
3606 <xs:element name="item" type="xs:string"
3607 minOccurs="0" maxOccurs="unbounded"/>
3608 </xs:sequence>
3609 </xs:complexType>
3610 </xs:element>
3611 </xs:schema>"#;
3612
3613 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3614 assert_eq!(schema.components.len(), 1);
3615
3616 let elem = &schema.components[0];
3618 let ct = elem
3619 .children
3620 .iter()
3621 .find(|c| c.component_type == XsdComponentType::ComplexType);
3622 assert!(ct.is_some());
3623 if let Some(ctc) = ct {
3624 let seq = ctc
3625 .children
3626 .iter()
3627 .find(|c| c.component_type == XsdComponentType::Sequence);
3628 assert!(seq.is_some());
3629 if let Some(seqc) = seq {
3630 assert!(!seqc.children.is_empty());
3631 let item = &seqc.children[0];
3632 assert_eq!(item.min_occurs, 0);
3633 assert_eq!(item.max_occurs, -1);
3634 }
3635 }
3636 }
3637
3638 #[test]
3639 fn test_parse_attribute_default() {
3640 let schema_xml = r#"<?xml version="1.0"?>
3641 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3642 <xs:element name="book">
3643 <xs:complexType>
3644 <xs:sequence>
3645 <xs:element name="title" type="xs:string"/>
3646 </xs:sequence>
3647 <xs:attribute name="lang" type="xs:string" default="en"/>
3648 <xs:attribute name="id" type="xs:integer" use="required"/>
3649 </xs:complexType>
3650 </xs:element>
3651 </xs:schema>"#;
3652
3653 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3654 let elem = &schema.components[0];
3655 let ct = elem
3656 .children
3657 .iter()
3658 .find(|c| c.component_type == XsdComponentType::ComplexType);
3659 assert!(ct.is_some());
3660 if let Some(ctc) = ct {
3661 let lang_attr = ctc
3662 .attributes
3663 .iter()
3664 .find(|a| a.name.as_deref() == Some("lang"));
3665 assert!(lang_attr.is_some());
3666 if let Some(la) = lang_attr {
3667 assert_eq!(la.min_occurs, 0); }
3669
3670 let id_attr = ctc
3671 .attributes
3672 .iter()
3673 .find(|a| a.name.as_deref() == Some("id"));
3674 assert!(id_attr.is_some());
3675 }
3676 }
3677
3678 #[test]
3679 fn test_parse_element_with_ref() {
3680 let schema_xml = r#"<?xml version="1.0"?>
3681 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3682 <xs:element name="root">
3683 <xs:complexType>
3684 <xs:sequence>
3685 <xs:element ref="child" minOccurs="0"/>
3686 </xs:sequence>
3687 </xs:complexType>
3688 </xs:element>
3689 <xs:element name="child" type="xs:string"/>
3690 </xs:schema>"#;
3691
3692 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3693 assert_eq!(schema.components.len(), 2);
3694 let root = &schema.components[0];
3696 let ct = root
3697 .children
3698 .iter()
3699 .find(|c| c.component_type == XsdComponentType::ComplexType);
3700 assert!(ct.is_some());
3701 if let Some(ctc) = ct {
3702 let seq = ctc
3703 .children
3704 .iter()
3705 .find(|c| c.component_type == XsdComponentType::Sequence);
3706 assert!(seq.is_some());
3707 if let Some(seqc) = seq {
3708 assert!(!seqc.children.is_empty());
3709 let ref_elem = &seqc.children[0];
3710 assert_eq!(ref_elem.ref_name, Some("child".to_string()));
3711 }
3712 }
3713 }
3714
3715 #[test]
3718 fn test_validate_simple_element() {
3719 let schema_xml = r#"<?xml version="1.0"?>
3720 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3721 <xs:element name="name" type="xs:string"/>
3722 </xs:schema>"#;
3723
3724 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3725
3726 let doc = r#"<?xml version="1.0"?>
3727 <name>John Doe</name>"#;
3728
3729 assert!(xsd_validate(&schema, doc).is_ok());
3730 }
3731
3732 #[test]
3733 fn test_validate_integer_element() {
3734 let schema_xml = r#"<?xml version="1.0"?>
3735 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3736 <xs:element name="age" type="xs:integer"/>
3737 </xs:schema>"#;
3738
3739 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3740
3741 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3742 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>not-a-number</age>"#).is_err());
3743 }
3744
3745 #[test]
3746 fn test_validate_complex_element() {
3747 let schema_xml = r#"<?xml version="1.0"?>
3748 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3749 <xs:element name="product">
3750 <xs:complexType>
3751 <xs:sequence>
3752 <xs:element name="name" type="xs:string"/>
3753 <xs:element name="price" type="xs:decimal"/>
3754 </xs:sequence>
3755 <xs:attribute name="id" type="xs:integer" use="required"/>
3756 </xs:complexType>
3757 </xs:element>
3758 </xs:schema>"#;
3759
3760 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3761
3762 let valid_doc = r#"<?xml version="1.0"?>
3763 <product id="123">
3764 <name>Widget</name>
3765 <price>9.99</price>
3766 </product>"#;
3767
3768 assert!(xsd_validate(&schema, valid_doc).is_ok());
3769 }
3770
3771 #[test]
3772 fn test_validate_missing_required_attribute() {
3773 let schema_xml = r#"<?xml version="1.0"?>
3774 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3775 <xs:element name="product">
3776 <xs:complexType>
3777 <xs:sequence>
3778 <xs:element name="name" type="xs:string"/>
3779 </xs:sequence>
3780 <xs:attribute name="id" type="xs:integer" use="required"/>
3781 </xs:complexType>
3782 </xs:element>
3783 </xs:schema>"#;
3784
3785 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3786
3787 let invalid_doc = r#"<?xml version="1.0"?>
3788 <product>
3789 <name>Widget</name>
3790 </product>"#;
3791
3792 assert!(xsd_validate(&schema, invalid_doc).is_err());
3793 }
3794
3795 #[test]
3796 fn test_validate_enumeration_facet() {
3797 let schema_xml = r#"<?xml version="1.0"?>
3798 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3799 <xs:element name="color">
3800 <xs:simpleType>
3801 <xs:restriction base="xs:string">
3802 <xs:enumeration value="red"/>
3803 <xs:enumeration value="green"/>
3804 <xs:enumeration value="blue"/>
3805 </xs:restriction>
3806 </xs:simpleType>
3807 </xs:element>
3808 </xs:schema>"#;
3809
3810 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3811
3812 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><color>red</color>"#).is_ok());
3815 }
3816
3817 #[test]
3818 fn test_validate_boolean_element() {
3819 let schema_xml = r#"<?xml version="1.0"?>
3820 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3821 <xs:element name="active" type="xs:boolean"/>
3822 </xs:schema>"#;
3823
3824 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3825
3826 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>true</active>"#).is_ok());
3827 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>false</active>"#).is_ok());
3828 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>1</active>"#).is_ok());
3829 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>yes</active>"#).is_err());
3830 }
3831
3832 #[test]
3833 fn test_validate_element_with_range_constraint() {
3834 let schema_xml = r#"<?xml version="1.0"?>
3835 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3836 <xs:element name="age">
3837 <xs:simpleType>
3838 <xs:restriction base="xs:integer">
3839 <xs:minInclusive value="0"/>
3840 <xs:maxInclusive value="150"/>
3841 </xs:restriction>
3842 </xs:simpleType>
3843 </xs:element>
3844 </xs:schema>"#;
3845
3846 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3847
3848 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3849 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>0</age>"#).is_ok());
3850 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>150</age>"#).is_ok());
3851 }
3853
3854 #[test]
3855 fn test_validate_optional_element() {
3856 let schema_xml = r#"<?xml version="1.0"?>
3857 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3858 <xs:element name="person">
3859 <xs:complexType>
3860 <xs:sequence>
3861 <xs:element name="name" type="xs:string"/>
3862 <xs:element name="nickname" type="xs:string" minOccurs="0"/>
3863 </xs:sequence>
3864 </xs:complexType>
3865 </xs:element>
3866 </xs:schema>"#;
3867
3868 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3869
3870 let doc_with_nick = r#"<?xml version="1.0"?>
3871 <person>
3872 <name>John</name>
3873 <nickname>Johnny</nickname>
3874 </person>"#;
3875
3876 let doc_without_nick = r#"<?xml version="1.0"?>
3877 <person>
3878 <name>John</name>
3879 </person>"#;
3880
3881 assert!(xsd_validate(&schema, doc_with_nick).is_ok());
3882 assert!(xsd_validate(&schema, doc_without_nick).is_ok());
3883 }
3884
3885 #[test]
3886 fn test_validate_unbounded_element() {
3887 let schema_xml = r#"<?xml version="1.0"?>
3888 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3889 <xs:element name="items">
3890 <xs:complexType>
3891 <xs:sequence>
3892 <xs:element name="item" type="xs:string"
3893 minOccurs="0" maxOccurs="unbounded"/>
3894 </xs:sequence>
3895 </xs:complexType>
3896 </xs:element>
3897 </xs:schema>"#;
3898
3899 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3900
3901 let doc = r#"<?xml version="1.0"?>
3902 <items>
3903 <item>one</item>
3904 <item>two</item>
3905 <item>three</item>
3906 </items>"#;
3907
3908 assert!(xsd_validate(&schema, doc).is_ok());
3909 }
3910
3911 #[test]
3912 fn test_validate_date_element() {
3913 let schema_xml = r#"<?xml version="1.0"?>
3914 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3915 <xs:element name="birthDate" type="xs:date"/>
3916 </xs:schema>"#;
3917
3918 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3919
3920 assert!(xsd_validate(
3921 &schema,
3922 r#"<?xml version="1.0"?><birthDate>1990-01-15</birthDate>"#
3923 )
3924 .is_ok());
3925 assert!(xsd_validate(
3926 &schema,
3927 r#"<?xml version="1.0"?><birthDate>not-a-date</birthDate>"#
3928 )
3929 .is_err());
3930 }
3931
3932 #[test]
3933 fn test_validate_choice() {
3934 let schema_xml = r#"<?xml version="1.0"?>
3935 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3936 <xs:element name="contact">
3937 <xs:complexType>
3938 <xs:choice>
3939 <xs:element name="email" type="xs:string"/>
3940 <xs:element name="phone" type="xs:string"/>
3941 </xs:choice>
3942 </xs:complexType>
3943 </xs:element>
3944 </xs:schema>"#;
3945
3946 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3947
3948 assert!(xsd_validate(
3949 &schema,
3950 r#"<?xml version="1.0"?><contact><email>a@b.com</email></contact>"#
3951 )
3952 .is_ok());
3953 assert!(xsd_validate(
3954 &schema,
3955 r#"<?xml version="1.0"?><contact><phone>555-1234</phone></contact>"#
3956 )
3957 .is_ok());
3958 }
3959
3960 #[test]
3961 fn test_validate_positive_integer_constraint() {
3962 let schema_xml = r#"<?xml version="1.0"?>
3963 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3964 <xs:element name="quantity" type="xs:positiveInteger"/>
3965 </xs:schema>"#;
3966
3967 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3968
3969 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>1</quantity>"#).is_ok());
3970 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>0</quantity>"#).is_err());
3971 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>-1</quantity>"#).is_err());
3972 }
3973
3974 #[test]
3985 fn test_xml_schema_new_mem_parser_ctxt() {
3986 let schema_xml = r#"<?xml version="1.0"?>
3987 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3988 <xs:element name="name" type="xs:string"/>
3989 </xs:schema>"#;
3990
3991 let ctxt = unsafe {
3992 xmlSchemaNewMemParserCtxt(
3993 schema_xml.as_ptr() as *const c_char,
3994 schema_xml.len() as c_int,
3995 )
3996 };
3997 assert!(!ctxt.is_null());
3998
3999 let schema = unsafe { xmlSchemaParse(ctxt) };
4000 assert!(!schema.is_null());
4001
4002 unsafe {
4003 xmlSchemaFree(schema);
4004 }
4005 }
4006
4007 #[test]
4017 fn test_xml_schema_validate_doc() {
4018 let schema_xml = r#"<?xml version="1.0"?>
4019 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4020 <xs:element name="name" type="xs:string"/>
4021 </xs:schema>"#;
4022
4023 let doc_xml = r#"<?xml version="1.0"?>
4024 <name>John Doe</name>"#;
4025
4026 let ctxt = unsafe {
4027 xmlSchemaNewMemParserCtxt(
4028 schema_xml.as_ptr() as *const c_char,
4029 schema_xml.len() as c_int,
4030 )
4031 };
4032 let schema = unsafe { xmlSchemaParse(ctxt) };
4033 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
4034
4035 let doc = unsafe {
4036 crate::abi::exports_xml2::xmlReadMemory(
4037 doc_xml.as_ptr() as *const c_char,
4038 doc_xml.len() as c_int,
4039 c"test.xml".as_ptr() as *const c_char,
4040 ptr::null(),
4041 0,
4042 )
4043 };
4044
4045 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
4046 assert_eq!(result, 0);
4047
4048 unsafe {
4049 xmlSchemaFreeValidCtxt(valid_ctxt);
4050 xmlSchemaFree(schema);
4051 crate::abi::exports_xml2::xmlFreeDoc(doc);
4052 }
4053 }
4054
4055 #[test]
4065 fn test_xml_schema_validate_invalid_doc() {
4066 let schema_xml = r#"<?xml version="1.0"?>
4067 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4068 <xs:element name="age" type="xs:integer"/>
4069 </xs:schema>"#;
4070
4071 let doc_xml = r#"<?xml version="1.0"?>
4072 <age>not-a-number</age>"#;
4073
4074 let ctxt = unsafe {
4075 xmlSchemaNewMemParserCtxt(
4076 schema_xml.as_ptr() as *const c_char,
4077 schema_xml.len() as c_int,
4078 )
4079 };
4080 let schema = unsafe { xmlSchemaParse(ctxt) };
4081 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
4082
4083 let doc = unsafe {
4084 crate::abi::exports_xml2::xmlReadMemory(
4085 doc_xml.as_ptr() as *const c_char,
4086 doc_xml.len() as c_int,
4087 c"test.xml".as_ptr() as *const c_char,
4088 ptr::null(),
4089 0,
4090 )
4091 };
4092
4093 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
4094 assert_ne!(result, 0); unsafe {
4097 xmlSchemaFreeValidCtxt(valid_ctxt);
4098 xmlSchemaFree(schema);
4099 crate::abi::exports_xml2::xmlFreeDoc(doc);
4100 }
4101 }
4102
4103 #[test]
4111 fn test_xml_schema_new_valid_ctxt_null() {
4112 let ctxt = unsafe { xmlSchemaNewValidCtxt(ptr::null_mut()) };
4113 assert!(!ctxt.is_null());
4114 unsafe { xmlSchemaFreeValidCtxt(ctxt) };
4115 }
4116
4117 #[test]
4125 fn test_xml_schema_free_null() {
4126 unsafe {
4127 xmlSchemaFree(ptr::null_mut());
4128 xmlSchemaFreeParserCtxt(ptr::null_mut());
4129 xmlSchemaFreeValidCtxt(ptr::null_mut());
4130 }
4131 }
4132
4133 #[test]
4141 fn test_xml_schema_new_parser_ctxt_null() {
4142 let ctxt = unsafe { xmlSchemaNewParserCtxt(ptr::null()) };
4143 assert!(!ctxt.is_null());
4144 unsafe {
4146 allocator::xmlFreeImpl(ctxt);
4147 }
4148 }
4149
4150 #[test]
4151 fn test_datatype_parse_kind() {
4152 assert_eq!(
4153 parse_datatype_kind("xs:string"),
4154 Some(XsdDatatypeKind::String)
4155 );
4156 assert_eq!(parse_datatype_kind("string"), Some(XsdDatatypeKind::String));
4157 assert_eq!(
4158 parse_datatype_kind("xs:integer"),
4159 Some(XsdDatatypeKind::Integer)
4160 );
4161 assert_eq!(
4162 parse_datatype_kind("xs:boolean"),
4163 Some(XsdDatatypeKind::Boolean)
4164 );
4165 assert_eq!(
4166 parse_datatype_kind("xs:decimal"),
4167 Some(XsdDatatypeKind::Decimal)
4168 );
4169 assert_eq!(
4170 parse_datatype_kind("xs:float"),
4171 Some(XsdDatatypeKind::Float)
4172 );
4173 assert_eq!(
4174 parse_datatype_kind("xs:double"),
4175 Some(XsdDatatypeKind::Double)
4176 );
4177 assert_eq!(parse_datatype_kind("xs:date"), Some(XsdDatatypeKind::Date));
4178 assert_eq!(
4179 parse_datatype_kind("xs:dateTime"),
4180 Some(XsdDatatypeKind::DateTime)
4181 );
4182 assert_eq!(parse_datatype_kind("xs:time"), Some(XsdDatatypeKind::Time));
4183 assert_eq!(
4184 parse_datatype_kind("xs:hexBinary"),
4185 Some(XsdDatatypeKind::HexBinary)
4186 );
4187 assert_eq!(
4188 parse_datatype_kind("xs:base64Binary"),
4189 Some(XsdDatatypeKind::Base64Binary)
4190 );
4191 assert_eq!(
4192 parse_datatype_kind("xs:anyURI"),
4193 Some(XsdDatatypeKind::AnyURI)
4194 );
4195 assert_eq!(
4196 parse_datatype_kind("xs:QName"),
4197 Some(XsdDatatypeKind::QName)
4198 );
4199 assert_eq!(
4200 parse_datatype_kind("xs:normalizedString"),
4201 Some(XsdDatatypeKind::NormalizedString)
4202 );
4203 assert_eq!(
4204 parse_datatype_kind("xs:token"),
4205 Some(XsdDatatypeKind::Token)
4206 );
4207 assert_eq!(
4208 parse_datatype_kind("xs:language"),
4209 Some(XsdDatatypeKind::Language)
4210 );
4211 assert_eq!(parse_datatype_kind("xs:Name"), Some(XsdDatatypeKind::Name));
4212 assert_eq!(
4213 parse_datatype_kind("xs:NCName"),
4214 Some(XsdDatatypeKind::NCName)
4215 );
4216 assert_eq!(parse_datatype_kind("xs:ID"), Some(XsdDatatypeKind::Id));
4217 assert_eq!(
4218 parse_datatype_kind("xs:IDREF"),
4219 Some(XsdDatatypeKind::Idref)
4220 );
4221 assert_eq!(
4222 parse_datatype_kind("xs:integer"),
4223 Some(XsdDatatypeKind::Integer)
4224 );
4225 assert_eq!(parse_datatype_kind("xs:long"), Some(XsdDatatypeKind::Long));
4226 assert_eq!(parse_datatype_kind("xs:int"), Some(XsdDatatypeKind::Int));
4227 assert_eq!(
4228 parse_datatype_kind("xs:short"),
4229 Some(XsdDatatypeKind::Short)
4230 );
4231 assert_eq!(parse_datatype_kind("xs:byte"), Some(XsdDatatypeKind::Byte));
4232 assert_eq!(
4233 parse_datatype_kind("xs:positiveInteger"),
4234 Some(XsdDatatypeKind::PositiveInteger)
4235 );
4236 assert_eq!(
4237 parse_datatype_kind("xs:negativeInteger"),
4238 Some(XsdDatatypeKind::NegativeInteger)
4239 );
4240 assert_eq!(parse_datatype_kind("unknown"), None);
4241 }
4242}