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> {
675 let doc_ptr = unsafe {
677 crate::abi::exports_xml2::xmlReadMemory(
678 xml_doc.as_ptr() as *const c_char,
679 xml_doc.len() as c_int,
680 c"schema.xsd".as_ptr() as *const c_char,
681 ptr::null(),
682 0,
683 )
684 };
685
686 if doc_ptr.is_null() {
687 return Err("Failed to parse schema XML document".to_string());
688 }
689
690 let result = unsafe { xsd_parse_schema_doc(doc_ptr) };
691 unsafe {
692 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
693 }
694 result
695}
696
697unsafe fn xsd_parse_schema_doc(doc: *mut _xmlDoc) -> Result<XsdSchema, String> {
703 unsafe {
704 let root = (*doc).children;
705 if root.is_null() {
706 return Err("Schema document has no root element".to_string());
707 }
708
709 let mut schema_node = root;
711 while !schema_node.is_null() && !node_is(schema_node, "schema") {
712 schema_node = (*schema_node).next;
713 }
714
715 if schema_node.is_null() {
716 return Err("Schema document root is not <schema>".to_string());
717 }
718
719 Ok(xsd_parse_schema_node(schema_node))
720 }
721}
722
723unsafe fn xsd_parse_schema_node(node: *mut _xmlNode) -> XsdSchema {
729 unsafe {
730 let mut schema = XsdSchema::new();
731 schema.target_namespace = get_attr(node, "targetNamespace");
732 schema.element_form_default = get_attr(node, "elementFormDefault");
733 schema.attribute_form_default = get_attr(node, "attributeFormDefault");
734
735 let mut child = (*node).children;
737 while !child.is_null() {
738 if (*child).type_ == XML_ELEMENT_NODE as c_int {
739 let comp = xsd_parse_component(child, &schema);
740 if comp.component_type != XsdComponentType::Annotation {
741 schema.components.push(comp);
742 }
743 }
744 child = (*child).next;
745 }
746
747 schema
748 }
749}
750
751unsafe fn xsd_parse_component(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
757 unsafe {
758 let name_str = if !(*node).name.is_null() {
760 let mut len = 0;
761 while *(*node).name.add(len) != 0 {
762 len += 1;
763 }
764 let slice = std::slice::from_raw_parts((*node).name, len);
765 if let Ok(s) = std::str::from_utf8(slice) {
766 if let Some(pos) = s.find(':') {
767 s[pos + 1..].to_string()
768 } else {
769 s.to_string()
770 }
771 } else {
772 String::new()
773 }
774 } else {
775 String::new()
776 };
777
778 match name_str.as_str() {
779 "element" => xsd_parse_element(node, schema),
780 "attribute" => xsd_parse_attribute_node(node, schema),
781 "complexType" => xsd_parse_complex_type(node, schema),
782 "simpleType" => xsd_parse_simple_type(node, schema),
783 "sequence" => xsd_parse_model_group(node, XsdComponentType::Sequence, schema),
784 "choice" => xsd_parse_model_group(node, XsdComponentType::Choice, schema),
785 "all" => xsd_parse_model_group(node, XsdComponentType::All, schema),
786 "restriction" => xsd_parse_restriction(node, schema),
787 "extension" => xsd_parse_extension(node, schema),
788 "list" => xsd_parse_list(node, schema),
789 "union" => xsd_parse_union(node, schema),
790 "annotation" => xsd_parse_annotation(node),
791 "any" => xsd_parse_any(node, schema),
792 "anyAttribute" => XsdComponent::new(XsdComponentType::AnyAttribute),
793 "group" => xsd_parse_group(node, schema),
794 "attributeGroup" => xsd_parse_attribute_group(node, schema),
795 "unique" => xsd_parse_identity_constraint(node, XsdComponentType::Unique, schema),
796 "key" => xsd_parse_identity_constraint(node, XsdComponentType::Key, schema),
797 "keyref" => xsd_parse_identity_constraint(node, XsdComponentType::KeyRef, schema),
798 "pattern" | "enumeration" | "minInclusive" | "maxInclusive" | "minExclusive"
800 | "maxExclusive" | "minLength" | "maxLength" | "length" | "whiteSpace"
801 | "fractionDigits" | "totalDigits" => xsd_parse_facet(node),
802 "simpleContent" => xsd_parse_simple_content(node, schema),
804 "complexContent" => xsd_parse_complex_content(node, schema),
805 _ => {
806 let mut comp = XsdComponent::new(XsdComponentType::Schema);
808 if let Ok(s) = std::str::from_utf8(std::slice::from_raw_parts((*node).name, {
809 let mut len = 0;
810 while *(*node).name.add(len) != 0 {
811 len += 1;
812 }
813 len
814 })) {
815 comp.name = Some(s.to_string());
816 }
817 comp
818 }
819 }
820 }
821}
822
823unsafe fn xsd_parse_element(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
829 unsafe {
830 let mut comp = XsdComponent::new(XsdComponentType::Element);
831 comp.name = get_attr(node, "name");
832 comp.ref_name = get_attr(node, "ref");
833 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
834 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
835 comp.is_abstract = get_attr_bool(node, "abstract");
836 comp.is_final = get_attr_bool(node, "final");
837 comp.substitution_group = get_attr(node, "substitutionGroup");
838 comp.form = get_attr(node, "form");
839
840 if let Some(type_name) = get_attr(node, "type") {
842 comp.datatype = parse_datatype_kind(&type_name);
843 if comp.datatype.is_none() {
845 comp.base = Some(type_name);
846 }
847 }
848
849 let _default = get_attr(node, "default");
851 let _fixed = get_attr(node, "fixed");
852
853 let mut child = (*node).children;
855 while !child.is_null() {
856 if (*child).type_ == XML_ELEMENT_NODE as c_int {
857 let child_comp = xsd_parse_component(child, schema);
858 match child_comp.component_type {
859 XsdComponentType::ComplexType | XsdComponentType::SimpleType => {
860 if let Some(ref name) = child_comp.name {
862 comp.base = Some(name.clone());
863 }
864 comp.children.push(child_comp);
865 }
866 XsdComponentType::Annotation => {
867 }
869 _ => {
870 comp.children.push(child_comp);
871 }
872 }
873 }
874 child = (*child).next;
875 }
876
877 comp
878 }
879}
880
881unsafe fn xsd_parse_attribute_node(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
887 unsafe {
888 let mut comp = XsdComponent::new(XsdComponentType::Attribute);
889 comp.name = get_attr(node, "name");
890 comp.ref_name = get_attr(node, "ref");
891 comp.form = get_attr(node, "form");
892
893 if let Some(type_name) = get_attr(node, "type") {
895 comp.datatype = parse_datatype_kind(&type_name);
896 if comp.datatype.is_none() {
897 comp.base = Some(type_name);
898 }
899 }
900
901 let use_attr = get_attr(node, "use");
903 if let Some(ref use_val) = use_attr {
904 if use_val == "required" {
905 comp.min_occurs = 1;
906 } else if use_val == "prohibited" {
907 comp.min_occurs = 0;
908 comp.max_occurs = 0;
909 } else {
910 comp.min_occurs = 0;
912 }
913 } else {
914 comp.min_occurs = 0; }
916
917 let _default = get_attr(node, "default");
918 let _fixed = get_attr(node, "fixed");
919
920 let mut child = (*node).children;
922 while !child.is_null() {
923 if (*child).type_ == XML_ELEMENT_NODE as c_int {
924 let child_comp = xsd_parse_component(child, schema);
925 if child_comp.component_type == XsdComponentType::SimpleType {
926 if let Some(ref name) = child_comp.name {
927 comp.base = Some(name.clone());
928 }
929 comp.children.push(child_comp);
930 }
931 }
932 child = (*child).next;
933 }
934
935 comp
936 }
937}
938
939unsafe fn xsd_parse_complex_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
945 unsafe {
946 let mut comp = XsdComponent::new(XsdComponentType::ComplexType);
947 comp.name = get_attr(node, "name");
948 comp.mixed = get_attr_bool(node, "mixed");
949 comp.is_abstract = get_attr_bool(node, "abstract");
950 comp.is_final = get_attr_bool(node, "final");
951
952 let mut child = (*node).children;
954 while !child.is_null() {
955 if (*child).type_ == XML_ELEMENT_NODE as c_int {
956 let child_comp = xsd_parse_component(child, schema);
957 match child_comp.component_type {
958 XsdComponentType::SimpleContent
959 | XsdComponentType::ComplexContent
960 | XsdComponentType::Sequence
961 | XsdComponentType::Choice
962 | XsdComponentType::All
963 | XsdComponentType::Group
964 | XsdComponentType::Any
965 | XsdComponentType::Annotation => {
966 if child_comp.component_type == XsdComponentType::SimpleContent {
967 comp.children.extend(child_comp.children);
969 } else if child_comp.component_type == XsdComponentType::ComplexContent {
970 comp.children.extend(child_comp.children);
972 } else {
973 comp.children.push(child_comp);
974 }
975 }
976 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
977 comp.attributes.push(child_comp);
978 }
979 _ => {
980 comp.children.push(child_comp);
981 }
982 }
983 }
984 child = (*child).next;
985 }
986
987 comp
988 }
989}
990
991unsafe fn xsd_parse_simple_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
997 unsafe {
998 let mut comp = XsdComponent::new(XsdComponentType::SimpleType);
999 comp.name = get_attr(node, "name");
1000
1001 let mut child = (*node).children;
1003 while !child.is_null() {
1004 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1005 let child_comp = xsd_parse_component(child, schema);
1006 match child_comp.component_type {
1007 XsdComponentType::Restriction
1008 | XsdComponentType::List
1009 | XsdComponentType::Union => {
1010 comp.datatype = child_comp.datatype;
1011 comp.base = child_comp.base;
1012 comp.facets = child_comp.facets;
1013 comp.children.extend(child_comp.children);
1014 }
1015 _ => {}
1016 }
1017 }
1018 child = (*child).next;
1019 }
1020
1021 comp
1022 }
1023}
1024
1025unsafe fn xsd_parse_model_group(
1031 node: *mut _xmlNode,
1032 ctype: XsdComponentType,
1033 schema: &XsdSchema,
1034) -> XsdComponent {
1035 unsafe {
1036 let mut comp = XsdComponent::new(ctype);
1037 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1038 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1039
1040 let mut child = (*node).children;
1041 while !child.is_null() {
1042 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1043 let child_comp = xsd_parse_component(child, schema);
1044 match child_comp.component_type {
1045 XsdComponentType::Annotation => {}
1046 _ => {
1047 comp.children.push(child_comp);
1048 }
1049 }
1050 }
1051 child = (*child).next;
1052 }
1053
1054 comp
1055 }
1056}
1057
1058unsafe fn xsd_parse_restriction(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1064 unsafe {
1065 let mut comp = XsdComponent::new(XsdComponentType::Restriction);
1066 comp.base = get_attr(node, "base");
1067
1068 if let Some(ref base_name) = comp.base {
1070 comp.datatype = parse_datatype_kind(base_name);
1071 }
1072
1073 let mut child = (*node).children;
1075 while !child.is_null() {
1076 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1077 let child_comp = xsd_parse_component(child, schema);
1078 match child_comp.component_type {
1079 XsdComponentType::Sequence
1080 | XsdComponentType::Choice
1081 | XsdComponentType::All
1082 | XsdComponentType::Group
1083 | XsdComponentType::Any
1084 | XsdComponentType::Annotation => {
1085 comp.children.push(child_comp);
1086 }
1087 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1088 comp.attributes.push(child_comp);
1089 }
1090 XsdComponentType::SimpleType => {
1091 comp.children.push(child_comp);
1093 }
1094 _ => {
1095 if let Some(facet_kind) =
1097 parse_facet_kind(&format!("{:?}", child_comp.component_type))
1098 {
1099 if let Some(val) = get_attr(child, "value") {
1101 comp.facets.push((facet_kind, val));
1102 }
1103 }
1104 let name_str = if !(*child).name.is_null() {
1106 let mut len = 0;
1107 while *(*child).name.add(len) != 0 {
1108 len += 1;
1109 }
1110 let slice = std::slice::from_raw_parts((*child).name, len);
1111 std::str::from_utf8(slice)
1112 .ok()
1113 .map(|s| {
1114 if let Some(pos) = s.find(':') {
1115 s[pos + 1..].to_string()
1116 } else {
1117 s.to_string()
1118 }
1119 })
1120 .unwrap_or_default()
1121 } else {
1122 String::new()
1123 };
1124 if !name_str.is_empty() {
1125 if let Some(facet_kind) = parse_facet_kind(&name_str) {
1126 if let Some(val) = get_attr(child, "value") {
1127 comp.facets.push((facet_kind, val));
1128 }
1129 }
1130 }
1131 }
1132 }
1133 }
1134 child = (*child).next;
1135 }
1136
1137 comp
1138 }
1139}
1140
1141unsafe fn xsd_parse_extension(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1147 unsafe {
1148 let mut comp = XsdComponent::new(XsdComponentType::Extension);
1149 comp.base = get_attr(node, "base");
1150
1151 if let Some(ref base_name) = comp.base {
1152 comp.datatype = parse_datatype_kind(base_name);
1153 }
1154
1155 let mut child = (*node).children;
1157 while !child.is_null() {
1158 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1159 let child_comp = xsd_parse_component(child, schema);
1160 match child_comp.component_type {
1161 XsdComponentType::Sequence
1162 | XsdComponentType::Choice
1163 | XsdComponentType::All
1164 | XsdComponentType::Group
1165 | XsdComponentType::Any
1166 | XsdComponentType::Annotation => {
1167 comp.children.push(child_comp);
1168 }
1169 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1170 comp.attributes.push(child_comp);
1171 }
1172 _ => {}
1173 }
1174 }
1175 child = (*child).next;
1176 }
1177
1178 comp
1179 }
1180}
1181
1182unsafe fn xsd_parse_list(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1188 unsafe {
1189 let mut comp = XsdComponent::new(XsdComponentType::List);
1190
1191 if let Some(item_type) = get_attr(node, "itemType") {
1192 comp.base = Some(item_type.clone());
1193 comp.datatype = parse_datatype_kind(&item_type);
1194 }
1195
1196 let mut child = (*node).children;
1198 while !child.is_null() {
1199 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1200 let child_comp = xsd_parse_component(child, schema);
1201 if child_comp.component_type == XsdComponentType::SimpleType {
1202 comp.datatype = child_comp.datatype;
1203 comp.base = child_comp.base;
1204 comp.facets = child_comp.facets;
1205 }
1206 }
1207 child = (*child).next;
1208 }
1209
1210 comp
1211 }
1212}
1213
1214unsafe fn xsd_parse_union(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1220 unsafe {
1221 let mut comp = XsdComponent::new(XsdComponentType::Union);
1222
1223 if let Some(member_types) = get_attr(node, "memberTypes") {
1224 comp.base = Some(member_types);
1225 }
1226
1227 let mut child = (*node).children;
1228 while !child.is_null() {
1229 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1230 let child_comp = xsd_parse_component(child, schema);
1231 if child_comp.component_type == XsdComponentType::SimpleType {
1232 comp.children.push(child_comp);
1233 }
1234 }
1235 child = (*child).next;
1236 }
1237
1238 comp
1239 }
1240}
1241
1242unsafe fn xsd_parse_annotation(node: *mut _xmlNode) -> XsdComponent {
1248 unsafe {
1249 let mut comp = XsdComponent::new(XsdComponentType::Annotation);
1250
1251 let mut child = (*node).children;
1252 while !child.is_null() {
1253 if (*child).type_ == XML_ELEMENT_NODE as c_int
1254 && (node_is(child, "documentation") || node_is(child, "appinfo"))
1255 {
1256 let text = get_node_text(child);
1257 if !text.is_empty() {
1258 comp.facets.push((XsdDatatypeKind::String, text));
1259 }
1260 }
1261 child = (*child).next;
1262 }
1263
1264 comp
1265 }
1266}
1267
1268unsafe fn xsd_parse_any(node: *mut _xmlNode, _schema: &XsdSchema) -> XsdComponent {
1274 unsafe {
1275 let mut comp = XsdComponent::new(XsdComponentType::Any);
1276 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1277 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1278
1279 let namespace_attr = get_attr(node, "namespace");
1280 if let Some(ref ns) = namespace_attr {
1281 if ns != "##any" {
1282 comp.target_namespace = Some(ns.clone());
1283 }
1284 }
1285
1286 comp
1287 }
1288}
1289
1290unsafe fn xsd_parse_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1296 unsafe {
1297 let mut comp = XsdComponent::new(XsdComponentType::Group);
1298 comp.name = get_attr(node, "name");
1299 comp.ref_name = get_attr(node, "ref");
1300 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1301 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1302
1303 let mut child = (*node).children;
1304 while !child.is_null() {
1305 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1306 let child_comp = xsd_parse_component(child, schema);
1307 match child_comp.component_type {
1308 XsdComponentType::Annotation => {}
1309 _ => {
1310 comp.children.push(child_comp);
1311 }
1312 }
1313 }
1314 child = (*child).next;
1315 }
1316
1317 comp
1318 }
1319}
1320
1321unsafe fn xsd_parse_attribute_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1327 unsafe {
1328 let mut comp = XsdComponent::new(XsdComponentType::AttributeGroup);
1329 comp.name = get_attr(node, "name");
1330 comp.ref_name = get_attr(node, "ref");
1331
1332 let mut child = (*node).children;
1333 while !child.is_null() {
1334 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1335 let child_comp = xsd_parse_component(child, schema);
1336 match child_comp.component_type {
1337 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1338 comp.attributes.push(child_comp);
1339 }
1340 _ => {}
1341 }
1342 }
1343 child = (*child).next;
1344 }
1345
1346 comp
1347 }
1348}
1349
1350unsafe fn xsd_parse_facet(node: *mut _xmlNode) -> XsdComponent {
1356 unsafe {
1357 let name_str = if !(*node).name.is_null() {
1358 let mut len = 0;
1359 while *(*node).name.add(len) != 0 {
1360 len += 1;
1361 }
1362 let slice = std::slice::from_raw_parts((*node).name, len);
1363 std::str::from_utf8(slice)
1364 .ok()
1365 .map(|s| {
1366 if let Some(pos) = s.find(':') {
1367 s[pos + 1..].to_string()
1368 } else {
1369 s.to_string()
1370 }
1371 })
1372 .unwrap_or_default()
1373 } else {
1374 String::new()
1375 };
1376
1377 let facet_kind = parse_facet_kind(&name_str).unwrap_or(XsdDatatypeKind::String);
1378 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1379 let val = get_attr(node, "value").unwrap_or_default();
1380 comp.facets.push((facet_kind, val));
1381 comp.datatype = Some(facet_kind);
1382
1383 comp
1384 }
1385}
1386
1387unsafe fn xsd_parse_simple_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1393 unsafe {
1394 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1395
1396 let mut child = (*node).children;
1397 while !child.is_null() {
1398 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1399 let child_comp = xsd_parse_component(child, schema);
1400 match child_comp.component_type {
1401 XsdComponentType::Restriction | XsdComponentType::Extension => {
1402 comp.children.push(child_comp);
1403 }
1404 _ => {}
1405 }
1406 }
1407 child = (*child).next;
1408 }
1409
1410 comp
1411 }
1412}
1413
1414unsafe fn xsd_parse_complex_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1420 unsafe {
1421 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1422
1423 let mut child = (*node).children;
1424 while !child.is_null() {
1425 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1426 let child_comp = xsd_parse_component(child, schema);
1427 match child_comp.component_type {
1428 XsdComponentType::Restriction | XsdComponentType::Extension => {
1429 comp.children.push(child_comp);
1430 }
1431 _ => {}
1432 }
1433 }
1434 child = (*child).next;
1435 }
1436
1437 comp
1438 }
1439}
1440
1441unsafe fn xsd_parse_identity_constraint(
1447 node: *mut _xmlNode,
1448 ctype: XsdComponentType,
1449 schema: &XsdSchema,
1450) -> XsdComponent {
1451 unsafe {
1452 let mut comp = XsdComponent::new(ctype);
1453 comp.name = get_attr(node, "name");
1454
1455 if ctype == XsdComponentType::KeyRef {
1456 comp.ref_name = get_attr(node, "refer");
1457 }
1458
1459 let mut child = (*node).children;
1460 while !child.is_null() {
1461 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1462 let child_comp = xsd_parse_component(child, schema);
1463 match child_comp.component_type {
1464 XsdComponentType::Selector | XsdComponentType::Field => {
1465 comp.children.push(child_comp);
1466 }
1467 _ => {}
1468 }
1469 }
1470 child = (*child).next;
1471 }
1472
1473 comp
1474 }
1475}
1476
1477pub fn xsd_validate_datatype(
1487 kind: &XsdDatatypeKind,
1488 value: &str,
1489 facets: &[(XsdDatatypeKind, String)],
1490) -> bool {
1491 if !validate_base_type(kind, value) {
1493 return false;
1494 }
1495
1496 let mut has_enumeration = false;
1501 let mut enumeration_match = false;
1502
1503 for (facet_kind, facet_value) in facets {
1504 if *facet_kind == XsdDatatypeKind::FacetEnumeration {
1505 has_enumeration = true;
1506 if xsd_validate_facet(kind, value, facet_kind, facet_value) {
1507 enumeration_match = true;
1508 }
1509 } else if !xsd_validate_facet(kind, value, facet_kind, facet_value) {
1510 return false;
1511 }
1512 }
1513
1514 if has_enumeration && !enumeration_match {
1516 return false;
1517 }
1518
1519 true
1520}
1521
1522pub fn xsd_validate_facet(
1524 _kind: &XsdDatatypeKind,
1525 value: &str,
1526 facet_kind: &XsdDatatypeKind,
1527 facet_value: &str,
1528) -> bool {
1529 match facet_kind {
1530 XsdDatatypeKind::FacetPattern => {
1531 match facet_value {
1534 r"\d+" => value.chars().all(|c| c.is_ascii_digit()),
1535 r"\d*" => value.is_empty() || value.chars().all(|c| c.is_ascii_digit()),
1536 r"[a-zA-Z]+" => value.chars().all(|c| c.is_ascii_alphabetic()),
1537 r"[a-zA-Z]*" => value.is_empty() || value.chars().all(|c| c.is_ascii_alphabetic()),
1538 r"[a-zA-Z0-9]+" => value.chars().all(|c| c.is_ascii_alphanumeric()),
1539 r"[a-zA-Z0-9_\-]+" => value
1540 .chars()
1541 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
1542 r"[a-zA-Z_][a-zA-Z0-9_\-\.]*" => {
1543 if value.is_empty() {
1544 return false;
1545 }
1546 let first = value.chars().next().unwrap();
1547 if !first.is_ascii_alphabetic() && first != '_' {
1548 return false;
1549 }
1550 value
1551 .chars()
1552 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1553 }
1554 r"[a-zA-Z_][\w\-\.]*" => {
1555 if value.is_empty() {
1556 return false;
1557 }
1558 let first = value.chars().next().unwrap();
1559 if !first.is_ascii_alphabetic() && first != '_' {
1560 return false;
1561 }
1562 value
1563 .chars()
1564 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1565 }
1566 r"\i\c*" => {
1567 if value.is_empty() {
1569 return false;
1570 }
1571 let first = value.chars().next().unwrap();
1572 if !is_name_start_char(first) {
1573 return false;
1574 }
1575 value.chars().skip(1).all(is_name_char)
1576 }
1577 r"\c+" => {
1578 if value.is_empty() {
1579 return false;
1580 }
1581 value.chars().all(is_name_char)
1582 }
1583 _ => {
1585 if facet_value.starts_with('^') && facet_value.ends_with('$') {
1586 let inner = &facet_value[1..facet_value.len() - 1];
1587 simple_glob_match(inner, value)
1588 } else {
1589 true
1591 }
1592 }
1593 }
1594 }
1595 XsdDatatypeKind::FacetEnumeration => {
1596 value == facet_value
1598 }
1599 XsdDatatypeKind::FacetMinInclusive => {
1600 compare_strings(value, facet_value) != std::cmp::Ordering::Less
1601 }
1602 XsdDatatypeKind::FacetMaxInclusive => {
1603 compare_strings(value, facet_value) != std::cmp::Ordering::Greater
1604 }
1605 XsdDatatypeKind::FacetMinExclusive => {
1606 compare_strings(value, facet_value) == std::cmp::Ordering::Greater
1607 }
1608 XsdDatatypeKind::FacetMaxExclusive => {
1609 compare_strings(value, facet_value) == std::cmp::Ordering::Less
1610 }
1611 XsdDatatypeKind::FacetMinLength => {
1612 let min = facet_value.parse::<usize>().unwrap_or(0);
1613 value.chars().count() >= min
1614 }
1615 XsdDatatypeKind::FacetMaxLength => {
1616 let max = facet_value.parse::<usize>().unwrap_or(usize::MAX);
1617 value.chars().count() <= max
1618 }
1619 XsdDatatypeKind::FacetLength => {
1620 let len = facet_value.parse::<usize>().unwrap_or(0);
1621 value.chars().count() == len
1622 }
1623 XsdDatatypeKind::FacetWhiteSpace => {
1624 match facet_value {
1626 "replace" => {
1627 true
1630 }
1631 "collapse" => {
1632 true
1634 }
1635 _ => true,
1636 }
1637 }
1638 XsdDatatypeKind::FacetFractionDigits | XsdDatatypeKind::FacetTotalDigits => {
1639 value.parse::<f64>().is_ok()
1641 }
1642 _ => true,
1643 }
1644}
1645
1646fn simple_glob_match(pattern: &str, value: &str) -> bool {
1648 let pattern_chars: Vec<char> = pattern.chars().collect();
1649 let value_chars: Vec<char> = value.chars().collect();
1650
1651 let mut pi = 0;
1652 let mut vi = 0;
1653 let mut backtrack_p = None;
1654 let mut backtrack_v = 0;
1655
1656 while vi < value_chars.len() {
1657 if pi < pattern_chars.len()
1658 && (pattern_chars[pi] == value_chars[vi] || pattern_chars[pi] == '.')
1659 {
1660 pi += 1;
1661 vi += 1;
1662 } else if pi < pattern_chars.len() && pattern_chars[pi] == '*' {
1663 backtrack_p = Some(pi);
1664 backtrack_v = vi + 1;
1665 pi += 1;
1666 } else if pi < pattern_chars.len() && pattern_chars[pi] == '+' {
1667 if pi + 1 < pattern_chars.len() && pattern_chars[pi + 1] == value_chars[vi] {
1669 pi += 1;
1670 vi += 1;
1671 while vi < value_chars.len() && value_chars[vi] == pattern_chars[pi] {
1673 vi += 1;
1674 }
1675 pi += 1;
1676 } else {
1677 return false;
1678 }
1679 } else if let Some(bp) = backtrack_p {
1680 pi = bp + 1;
1681 vi = backtrack_v;
1682 backtrack_v += 1;
1683 } else {
1684 return false;
1685 }
1686 }
1687
1688 while pi < pattern_chars.len() && (pattern_chars[pi] == '*' || pattern_chars[pi] == '+') {
1690 if pattern_chars[pi] == '+' && vi == value_chars.len() {
1691 return false; }
1693 pi += 1;
1694 }
1695
1696 pi == pattern_chars.len()
1697}
1698
1699const fn is_name_start_char(c: char) -> bool {
1701 c.is_ascii_alphabetic()
1702 || c == '_'
1703 || c == ':'
1704 || (c >= '\u{00C0}' && c <= '\u{00D6}')
1705 || (c >= '\u{00D8}' && c <= '\u{00F6}')
1706 || (c >= '\u{00F8}' && c <= '\u{02FF}')
1707 || (c >= '\u{0370}' && c <= '\u{037D}')
1708 || (c >= '\u{037F}' && c <= '\u{1FFF}')
1709 || (c >= '\u{200C}' && c <= '\u{200D}')
1710 || (c >= '\u{2070}' && c <= '\u{218F}')
1711 || (c >= '\u{2C00}' && c <= '\u{2FEF}')
1712 || (c >= '\u{3001}' && c <= '\u{D7FF}')
1713 || (c >= '\u{F900}' && c <= '\u{FDCF}')
1714 || (c >= '\u{FDF0}' && c <= '\u{FFFD}')
1715}
1716
1717const fn is_name_char(c: char) -> bool {
1719 is_name_start_char(c)
1720 || c.is_ascii_digit()
1721 || c == '-'
1722 || c == '.'
1723 || c == '\u{00B7}'
1724 || (c >= '\u{0300}' && c <= '\u{036F}')
1725 || (c >= '\u{203F}' && c <= '\u{2040}')
1726}
1727
1728fn compare_strings(a: &str, b: &str) -> std::cmp::Ordering {
1730 if let (Ok(na), Ok(nb)) = (a.parse::<f64>(), b.parse::<f64>()) {
1732 return na.partial_cmp(&nb).unwrap_or(std::cmp::Ordering::Equal);
1733 }
1734 if let (Ok(na), Ok(nb)) = (a.parse::<i64>(), b.parse::<i64>()) {
1736 return na.cmp(&nb);
1737 }
1738 a.cmp(b)
1740}
1741
1742fn validate_base_type(kind: &XsdDatatypeKind, value: &str) -> bool {
1744 match kind {
1745 XsdDatatypeKind::String => true,
1746 XsdDatatypeKind::NormalizedString => {
1747 !value.contains('\t') && !value.contains('\n') && !value.contains('\r')
1749 }
1750 XsdDatatypeKind::Token => {
1751 if value.is_empty() {
1753 return true;
1754 }
1755 if value.starts_with(' ') || value.ends_with(' ') {
1756 return false;
1757 }
1758 !value.contains(" ")
1759 && !value.contains('\t')
1760 && !value.contains('\n')
1761 && !value.contains('\r')
1762 }
1763 XsdDatatypeKind::Language => {
1764 if value.is_empty() {
1767 return false;
1768 }
1769 let segments: Vec<&str> = value.split('-').collect();
1770 if segments.is_empty() {
1771 return false;
1772 }
1773 if segments[0].is_empty() || !segments[0].chars().all(|c| c.is_ascii_alphabetic()) {
1775 return false;
1776 }
1777 if segments[0].len() > 8 {
1778 return false;
1779 }
1780 for seg in &segments[1..] {
1782 if seg.is_empty() || seg.len() > 8 {
1783 return false;
1784 }
1785 if !seg.chars().all(|c| c.is_ascii_alphanumeric()) {
1786 return false;
1787 }
1788 }
1789 true
1790 }
1791 XsdDatatypeKind::Name => {
1792 if value.is_empty() {
1793 return false;
1794 }
1795 let mut chars = value.chars();
1796 let first = chars.next().unwrap();
1797 if !is_name_start_char(first) {
1798 return false;
1799 }
1800 chars.all(is_name_char)
1801 }
1802 XsdDatatypeKind::NCName
1803 | XsdDatatypeKind::Id
1804 | XsdDatatypeKind::Idref
1805 | XsdDatatypeKind::Entity => {
1806 if value.is_empty() || value.contains(':') {
1808 return false;
1809 }
1810 let mut chars = value.chars();
1811 let first = chars.next().unwrap();
1812 if !is_name_start_char(first) {
1813 return false;
1814 }
1815 chars.all(is_name_char)
1816 }
1817 XsdDatatypeKind::Boolean => {
1818 matches!(value, "true" | "false" | "1" | "0")
1819 }
1820 XsdDatatypeKind::Decimal
1821 | XsdDatatypeKind::Integer
1822 | XsdDatatypeKind::NonPositiveInteger
1823 | XsdDatatypeKind::NegativeInteger
1824 | XsdDatatypeKind::Long
1825 | XsdDatatypeKind::Int
1826 | XsdDatatypeKind::Short
1827 | XsdDatatypeKind::Byte
1828 | XsdDatatypeKind::NonNegativeInteger
1829 | XsdDatatypeKind::UnsignedLong
1830 | XsdDatatypeKind::UnsignedInt
1831 | XsdDatatypeKind::UnsignedShort
1832 | XsdDatatypeKind::UnsignedByte
1833 | XsdDatatypeKind::PositiveInteger => {
1834 if value.is_empty() {
1836 return false;
1837 }
1838 let mut chars = value.chars().peekable();
1839 if *chars.peek().unwrap_or(&'\0') == '-' || *chars.peek().unwrap_or(&'\0') == '+' {
1840 chars.next();
1841 }
1842 let mut has_dot = false;
1843 let mut has_digit = false;
1844 for c in chars {
1845 if c == '.' {
1846 if has_dot {
1847 return false;
1848 }
1849 has_dot = true;
1850 } else if c.is_ascii_digit() {
1851 has_digit = true;
1852 } else {
1853 return false;
1854 }
1855 }
1856 if !has_digit {
1857 return false;
1858 }
1859
1860 if has_dot && *kind != XsdDatatypeKind::Decimal {
1863 return false;
1864 }
1865
1866 match kind {
1867 XsdDatatypeKind::NonPositiveInteger => {
1868 if let Ok(v) = value.parse::<i64>() {
1869 v <= 0
1870 } else {
1871 false
1872 }
1873 }
1874 XsdDatatypeKind::NegativeInteger => {
1875 if let Ok(v) = value.parse::<i64>() {
1876 v < 0
1877 } else {
1878 false
1879 }
1880 }
1881 XsdDatatypeKind::NonNegativeInteger => {
1882 if let Ok(v) = value.parse::<i64>() {
1883 v >= 0
1884 } else {
1885 false
1886 }
1887 }
1888 XsdDatatypeKind::PositiveInteger => {
1889 if let Ok(v) = value.parse::<i64>() {
1890 v > 0
1891 } else {
1892 false
1893 }
1894 }
1895 XsdDatatypeKind::UnsignedLong
1896 | XsdDatatypeKind::UnsignedInt
1897 | XsdDatatypeKind::UnsignedShort
1898 | XsdDatatypeKind::UnsignedByte => {
1899 if let Ok(v) = value.parse::<u64>() {
1900 match kind {
1901 XsdDatatypeKind::UnsignedInt => v <= u64::from(u32::MAX),
1902 XsdDatatypeKind::UnsignedShort => v <= u64::from(u16::MAX),
1903 XsdDatatypeKind::UnsignedByte => v <= u64::from(u8::MAX),
1904 _ => true,
1905 }
1906 } else {
1907 false
1908 }
1909 }
1910 XsdDatatypeKind::Long => value.parse::<i64>().is_ok(),
1911 XsdDatatypeKind::Int => value.parse::<i32>().is_ok(),
1912 XsdDatatypeKind::Short => value.parse::<i16>().is_ok(),
1913 XsdDatatypeKind::Byte => value.parse::<i8>().is_ok(),
1914 _ => true,
1915 }
1916 }
1917 XsdDatatypeKind::Float | XsdDatatypeKind::Double => {
1918 matches!(value, "INF" | "-INF" | "NaN") || value.parse::<f64>().is_ok()
1920 }
1921 XsdDatatypeKind::Duration => {
1922 if !value.starts_with('-') && !value.starts_with('P') {
1924 return false;
1925 }
1926 let dur = value.strip_prefix('-').unwrap_or(value);
1927 if !dur.starts_with('P') {
1928 return false;
1929 }
1930 let rest = &dur[1..];
1931 if rest.is_empty() {
1932 return false;
1933 }
1934 let has_t = rest.contains('T');
1935 let _date_part = if has_t {
1936 &rest[..rest.find('T').unwrap()]
1937 } else {
1938 rest
1939 };
1940 if has_t {
1941 let time_part = &rest[rest.find('T').unwrap() + 1..];
1942 if time_part.is_empty() {
1943 return false;
1944 }
1945 }
1946 true
1947 }
1948 XsdDatatypeKind::DateTime => {
1949 if value.len() < 19 {
1951 return false;
1952 }
1953 let chars: Vec<char> = value.chars().collect();
1954 chars[4] == '-'
1955 && chars[7] == '-'
1956 && chars[10] == 'T'
1957 && chars[13] == ':'
1958 && chars[16] == ':'
1959 }
1960 XsdDatatypeKind::Date => {
1961 if value.len() < 10 {
1963 return false;
1964 }
1965 let chars: Vec<char> = value.chars().collect();
1966 chars[4] == '-' && chars[7] == '-'
1967 }
1968 XsdDatatypeKind::Time => {
1969 if value.len() < 8 {
1971 return false;
1972 }
1973 let chars: Vec<char> = value.chars().collect();
1974 chars[2] == ':' && chars[5] == ':'
1975 }
1976 XsdDatatypeKind::GYear => {
1977 if value.len() < 4 {
1979 return false;
1980 }
1981 value.chars().take(4).all(|c| c.is_ascii_digit())
1982 }
1983 XsdDatatypeKind::GYearMonth => {
1984 if value.len() < 7 {
1986 return false;
1987 }
1988 let chars: Vec<char> = value.chars().collect();
1989 chars[4] == '-'
1990 }
1991 XsdDatatypeKind::GMonthDay => {
1992 if value.len() < 6 || !value.starts_with("--") {
1994 return false;
1995 }
1996 let chars: Vec<char> = value.chars().collect();
1997 chars[4] == '-'
1998 }
1999 XsdDatatypeKind::GDay => {
2000 value.starts_with("---") && value.len() >= 4
2002 }
2003 XsdDatatypeKind::GMonth => {
2004 value.starts_with("--") && value.len() >= 3
2006 }
2007 XsdDatatypeKind::HexBinary => {
2008 if !value.len().is_multiple_of(2) {
2009 return false;
2010 }
2011 value.chars().all(|c| c.is_ascii_hexdigit())
2012 }
2013 XsdDatatypeKind::Base64Binary => {
2014 if value.is_empty() {
2016 return true;
2017 }
2018 let valid_chars =
2019 |c: char| c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=';
2020 value.chars().all(valid_chars)
2021 }
2022 XsdDatatypeKind::AnyURI => {
2023 !value.is_empty()
2025 }
2026 XsdDatatypeKind::QName => {
2027 if let Some(pos) = value.find(':') {
2029 let prefix = &value[..pos];
2030 let local = &value[pos + 1..];
2031 is_ncname(prefix) && is_ncname(local)
2032 } else {
2033 is_ncname(value)
2034 }
2035 }
2036 XsdDatatypeKind::Notation => {
2037 !value.is_empty()
2039 }
2040 XsdDatatypeKind::Nmtoken => !value.is_empty() && value.chars().all(is_name_char),
2041 XsdDatatypeKind::Nmtokens => {
2042 !value.is_empty()
2043 && value
2044 .split_whitespace()
2045 .all(|t| !t.is_empty() && t.chars().all(is_name_char))
2046 }
2047 XsdDatatypeKind::Idrefs | XsdDatatypeKind::Entities => {
2048 !value.is_empty() && value.split_whitespace().all(is_ncname)
2049 }
2050 XsdDatatypeKind::FacetPattern
2052 | XsdDatatypeKind::FacetEnumeration
2053 | XsdDatatypeKind::FacetMinInclusive
2054 | XsdDatatypeKind::FacetMaxInclusive
2055 | XsdDatatypeKind::FacetMinExclusive
2056 | XsdDatatypeKind::FacetMaxExclusive
2057 | XsdDatatypeKind::FacetMinLength
2058 | XsdDatatypeKind::FacetMaxLength
2059 | XsdDatatypeKind::FacetLength
2060 | XsdDatatypeKind::FacetWhiteSpace
2061 | XsdDatatypeKind::FacetFractionDigits
2062 | XsdDatatypeKind::FacetTotalDigits => true,
2063 }
2064}
2065
2066fn is_ncname(value: &str) -> bool {
2068 if value.is_empty() {
2069 return false;
2070 }
2071 let first = value.chars().next().unwrap();
2072 if !is_name_start_char(first) || first == ':' {
2073 return false;
2074 }
2075 value.chars().skip(1).all(|c| is_name_char(c) && c != ':')
2076}
2077
2078pub fn xsd_validate(schema: &XsdSchema, doc: &str) -> Result<(), Vec<String>> {
2088 let doc_ptr = unsafe {
2089 crate::abi::exports_xml2::xmlReadMemory(
2090 doc.as_ptr() as *const c_char,
2091 doc.len() as c_int,
2092 c"doc.xml".as_ptr() as *const c_char,
2093 ptr::null(),
2094 0,
2095 )
2096 };
2097
2098 if doc_ptr.is_null() {
2099 return Err(vec!["Failed to parse XML document".to_string()]);
2100 }
2101
2102 let mut ctxt = XsdValidCtxt::new();
2103 ctxt.schema = Some(schema.clone());
2104
2105 let result = unsafe { xsd_validate_doc(schema, doc_ptr, &mut ctxt) };
2106
2107 unsafe {
2108 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
2109 }
2110
2111 if result {
2112 Ok(())
2113 } else {
2114 Err(ctxt.errors)
2115 }
2116}
2117
2118unsafe fn xsd_validate_doc(schema: &XsdSchema, doc: *mut _xmlDoc, ctxt: &mut XsdValidCtxt) -> bool {
2124 unsafe {
2125 let root = (*doc).children;
2126 if root.is_null() {
2127 ctxt.errors.push("Document has no root element".to_string());
2128 ctxt.nb_errors += 1;
2129 return false;
2130 }
2131
2132 let mut root_elem = root;
2134 while !root_elem.is_null() && (*root_elem).type_ != XML_ELEMENT_NODE as c_int {
2135 root_elem = (*root_elem).next;
2136 }
2137
2138 if root_elem.is_null() {
2139 ctxt.errors.push("Document has no root element".to_string());
2140 ctxt.nb_errors += 1;
2141 return false;
2142 }
2143
2144 let root_name = get_node_qname(root_elem);
2146
2147 let global_elem = schema.components.iter().find(|c| {
2149 c.component_type == XsdComponentType::Element && c.name.as_deref() == Some(&root_name)
2150 });
2151
2152 if let Some(global) = global_elem {
2153 xsd_validate_element(global, root_elem, schema, ctxt)
2154 } else {
2155 let mut valid = true;
2157 for component in &schema.components {
2158 if component.component_type == XsdComponentType::Element {
2159 if let Some(ref name) = component.name {
2160 if *name == root_name {
2161 valid = xsd_validate_element(component, root_elem, schema, ctxt);
2162 break;
2163 }
2164 }
2165 }
2166 }
2167 valid
2168 }
2169 }
2170}
2171
2172fn xsd_validate_element(
2178 component: &XsdComponent,
2179 node: *mut _xmlNode,
2180 schema: &XsdSchema,
2181 ctxt: &mut XsdValidCtxt,
2182) -> bool {
2183 unsafe {
2184 let mut valid = true;
2185
2186 let node_name = get_node_qname(node);
2188
2189 if let Some(ref comp_name) = component.name {
2191 if comp_name != &node_name {
2192 ctxt.errors.push(format!(
2193 "Element '{}' does not match expected '{}'",
2194 node_name, comp_name
2195 ));
2196 ctxt.nb_errors += 1;
2197 return false;
2198 }
2199 }
2200
2201 let type_comp = component.children.iter().find(|c| {
2203 c.component_type == XsdComponentType::ComplexType
2204 || c.component_type == XsdComponentType::SimpleType
2205 });
2206
2207 if let Some(tc) = type_comp {
2208 match tc.component_type {
2209 XsdComponentType::ComplexType => {
2210 valid &= xsd_validate_complex_type(tc, node, schema, ctxt);
2211 }
2212 XsdComponentType::SimpleType => {
2213 let text = get_node_text(node);
2214 if let Some(ref dt) = tc.datatype {
2215 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2216 ctxt.errors.push(format!(
2217 "Element '{}' has invalid value '{}' for type '{:?}'",
2218 node_name, text, dt
2219 ));
2220 ctxt.nb_errors += 1;
2221 valid = false;
2222 }
2223 }
2224 }
2225 _ => {}
2226 }
2227 } else if let Some(ref dt) = component.datatype {
2228 let text = get_node_text(node);
2230 if !xsd_validate_datatype(dt, &text, &component.facets) {
2231 ctxt.errors.push(format!(
2232 "Element '{}' has invalid value '{}' for type '{:?}'",
2233 node_name, text, dt
2234 ));
2235 ctxt.nb_errors += 1;
2236 valid = false;
2237 }
2238 } else {
2239 valid &= xsd_validate_content(component, node, schema, ctxt);
2241 }
2242
2243 valid
2244 }
2245}
2246
2247fn xsd_validate_complex_type(
2253 component: &XsdComponent,
2254 node: *mut _xmlNode,
2255 schema: &XsdSchema,
2256 ctxt: &mut XsdValidCtxt,
2257) -> bool {
2258 {
2259 let mut valid = true;
2260
2261 for attr in &component.attributes {
2263 match attr.component_type {
2264 XsdComponentType::Attribute => {
2265 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2266 }
2267 XsdComponentType::AnyAttribute => {
2268 }
2270 _ => {}
2271 }
2272 }
2273
2274 for child in &component.children {
2276 match child.component_type {
2277 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2278 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2279 }
2280 XsdComponentType::Restriction | XsdComponentType::Extension => {
2281 valid &= xsd_validate_restriction_extension(child, node, schema, ctxt);
2283 }
2284 XsdComponentType::Any => {
2285 }
2287 _ => {}
2288 }
2289 }
2290
2291 valid
2292 }
2293}
2294
2295fn xsd_validate_model_group(
2301 component: &XsdComponent,
2302 node: *mut _xmlNode,
2303 _schema: &XsdSchema,
2304 ctxt: &mut XsdValidCtxt,
2305) -> bool {
2306 unsafe {
2307 let mut valid = true;
2308
2309 let mut child_nodes: Vec<*mut _xmlNode> = Vec::new();
2311 let mut child = (*node).children;
2312 while !child.is_null() {
2313 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2314 child_nodes.push(child);
2315 }
2316 child = (*child).next;
2317 }
2318
2319 match component.component_type {
2320 XsdComponentType::Sequence => {
2321 let mut child_idx = 0;
2323 for part in &component.children {
2324 let min = part.min_occurs;
2325 let max = part.max_occurs;
2326 let match_name = part.name.as_deref().unwrap_or("");
2327 let match_ref = part.ref_name.as_deref().unwrap_or("");
2328
2329 let mut count = 0;
2330 while child_idx < child_nodes.len() && (max == -1 || count < max) {
2331 let child_node = child_nodes[child_idx];
2332 let child_name = get_node_qname(child_node);
2333
2334 if part.component_type == XsdComponentType::Any
2335 || (!match_name.is_empty() && child_name == match_name)
2336 || (!match_ref.is_empty() && child_name == match_ref)
2337 {
2338 count += 1;
2339 child_idx += 1;
2340 } else if count >= min {
2341 break;
2342 } else {
2343 ctxt.errors.push(format!(
2344 "Expected element '{}' but found '{}'",
2345 match_name, child_name
2346 ));
2347 ctxt.nb_errors += 1;
2348 valid = false;
2349 child_idx += 1;
2350 break;
2351 }
2352 }
2353
2354 if count < min {
2355 ctxt.errors.push(format!(
2356 "Element '{}' occurs {} times, minimum is {}",
2357 if match_name.is_empty() {
2358 "?"
2359 } else {
2360 match_name
2361 },
2362 count,
2363 min
2364 ));
2365 ctxt.nb_errors += 1;
2366 valid = false;
2367 }
2368 }
2369
2370 if child_idx < child_nodes.len() {
2372 let extra = get_node_qname(child_nodes[child_idx]);
2373 ctxt.errors
2374 .push(format!("Unexpected element '{}' in sequence", extra));
2375 ctxt.nb_errors += 1;
2376 valid = false;
2377 }
2378 }
2379 XsdComponentType::Choice => {
2380 let mut matched = false;
2382 for child_node in &child_nodes {
2383 let child_name = get_node_qname(*child_node);
2384 for part in &component.children {
2385 let match_name = part.name.as_deref().unwrap_or("");
2386 let match_ref = part.ref_name.as_deref().unwrap_or("");
2387
2388 if part.component_type == XsdComponentType::Any {
2389 matched = true;
2390 } else if (!match_name.is_empty() && child_name == match_name)
2391 || (!match_ref.is_empty() && child_name == match_ref)
2392 {
2393 matched = true;
2394 break;
2395 }
2396 }
2397 if !matched {
2398 ctxt.errors
2399 .push(format!("Element '{}' is not valid in choice", child_name));
2400 ctxt.nb_errors += 1;
2401 valid = false;
2402 }
2403 matched = false; }
2405 }
2406 XsdComponentType::All => {
2407 for child_node in &child_nodes {
2409 let child_name = get_node_qname(*child_node);
2410 let mut matched = false;
2411 for part in &component.children {
2412 let match_name = part.name.as_deref().unwrap_or("");
2413 if !match_name.is_empty() && child_name == match_name {
2414 matched = true;
2415 break;
2416 }
2417 }
2418 if !matched {
2419 ctxt.errors.push(format!(
2420 "Element '{}' is not valid in all group",
2421 child_name
2422 ));
2423 ctxt.nb_errors += 1;
2424 valid = false;
2425 }
2426 }
2427 }
2428 _ => {}
2429 }
2430
2431 valid
2432 }
2433}
2434
2435fn xsd_validate_restriction_extension(
2441 component: &XsdComponent,
2442 node: *mut _xmlNode,
2443 schema: &XsdSchema,
2444 ctxt: &mut XsdValidCtxt,
2445) -> bool {
2446 unsafe {
2447 let mut valid = true;
2448
2449 for attr in &component.attributes {
2451 if attr.component_type == XsdComponentType::Attribute {
2452 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2453 }
2454 }
2455
2456 for child in &component.children {
2458 match child.component_type {
2459 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2460 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2461 }
2462 _ => {}
2463 }
2464 }
2465
2466 if let Some(ref dt) = component.datatype {
2468 let text = get_node_text(node);
2469 if !xsd_validate_datatype(dt, &text, &component.facets) {
2470 let node_name = get_node_qname(node);
2471 ctxt.errors.push(format!(
2472 "Element '{}' has invalid value '{}' for type '{:?}'",
2473 node_name, text, dt
2474 ));
2475 ctxt.nb_errors += 1;
2476 valid = false;
2477 }
2478 }
2479
2480 valid
2481 }
2482}
2483
2484fn xsd_validate_attribute(
2490 component: &XsdComponent,
2491 node: *mut _xmlNode,
2492 _schema: &XsdSchema,
2493 ctxt: &mut XsdValidCtxt,
2494) -> bool {
2495 unsafe {
2496 let attr_name = component.name.as_deref().unwrap_or("");
2497 if attr_name.is_empty() {
2498 return true;
2499 }
2500
2501 let attr_value = get_attr(node, attr_name);
2503
2504 let is_required = component.min_occurs > 0;
2505
2506 match attr_value {
2507 Some(ref val) => {
2508 if let Some(ref dt) = component.datatype {
2510 if !xsd_validate_datatype(dt, val, &component.facets) {
2511 ctxt.errors.push(format!(
2512 "Attribute '{}' has invalid value '{}' for type '{:?}'",
2513 attr_name, val, dt
2514 ));
2515 ctxt.nb_errors += 1;
2516 return false;
2517 }
2518 }
2519 true
2520 }
2521 None => {
2522 if is_required {
2523 ctxt.errors
2524 .push(format!("Required attribute '{}' is missing", attr_name));
2525 ctxt.nb_errors += 1;
2526 false
2527 } else {
2528 true
2529 }
2530 }
2531 }
2532 }
2533}
2534
2535fn xsd_validate_content(
2541 component: &XsdComponent,
2542 node: *mut _xmlNode,
2543 schema: &XsdSchema,
2544 ctxt: &mut XsdValidCtxt,
2545) -> bool {
2546 {
2547 let mut valid = true;
2548
2549 for child_comp in &component.children {
2550 match child_comp.component_type {
2551 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2552 valid &= xsd_validate_model_group(child_comp, node, schema, ctxt);
2553 }
2554 XsdComponentType::Element => {
2555 valid &= xsd_validate_element_inline(child_comp, node, schema, ctxt);
2557 }
2558 _ => {}
2559 }
2560 }
2561
2562 valid
2563 }
2564}
2565
2566fn xsd_validate_element_inline(
2572 component: &XsdComponent,
2573 node: *mut _xmlNode,
2574 schema: &XsdSchema,
2575 ctxt: &mut XsdValidCtxt,
2576) -> bool {
2577 unsafe {
2578 let mut valid = true;
2579 let mut child = (*node).children;
2580
2581 while !child.is_null() {
2582 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2583 let child_name = get_node_qname(child);
2584
2585 let match_name = component.name.as_deref().unwrap_or("");
2586 let match_ref = component.ref_name.as_deref().unwrap_or("");
2587
2588 if (!match_name.is_empty() && child_name == match_name)
2589 || (!match_ref.is_empty() && child_name == match_ref)
2590 {
2591 let type_comp = component.children.iter().find(|c| {
2593 c.component_type == XsdComponentType::ComplexType
2594 || c.component_type == XsdComponentType::SimpleType
2595 });
2596
2597 if let Some(tc) = type_comp {
2598 match tc.component_type {
2599 XsdComponentType::ComplexType => {
2600 valid &= xsd_validate_complex_type(tc, child, schema, ctxt);
2601 }
2602 XsdComponentType::SimpleType => {
2603 let text = get_node_text(child);
2604 if let Some(ref dt) = tc.datatype {
2605 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2606 ctxt.errors.push(format!(
2607 "Element '{}' has invalid value '{}'",
2608 child_name, text
2609 ));
2610 ctxt.nb_errors += 1;
2611 valid = false;
2612 }
2613 }
2614 }
2615 _ => {}
2616 }
2617 }
2618 }
2619 }
2620 child = (*child).next;
2621 }
2622
2623 valid
2624 }
2625}
2626
2627unsafe fn get_node_qname(node: *mut _xmlNode) -> String {
2633 if node.is_null() {
2634 return String::new();
2635 }
2636 unsafe {
2637 let ns = (*node).ns;
2639 let prefix = if !ns.is_null() && !(*ns).prefix.is_null() {
2640 let mut len = 0;
2641 while *(*ns).prefix.add(len) != 0 {
2642 len += 1;
2643 }
2644 let slice = std::slice::from_raw_parts((*ns).prefix, len);
2645 if let Ok(s) = std::str::from_utf8(slice) {
2646 format!("{}:", s)
2647 } else {
2648 String::new()
2649 }
2650 } else {
2651 String::new()
2652 };
2653
2654 let name = (*node).name;
2655 if name.is_null() {
2656 return String::new();
2657 }
2658 let mut len = 0;
2659 while *name.add(len) != 0 {
2660 len += 1;
2661 }
2662 let slice = std::slice::from_raw_parts(name, len);
2663 if let Ok(s) = std::str::from_utf8(slice) {
2664 format!("{}{}", prefix, s)
2665 } else {
2666 String::new()
2667 }
2668 }
2669}
2670
2671#[no_mangle]
2690pub unsafe extern "C" fn xmlSchemaNewParserCtxt(url: *const c_char) -> *mut c_void {
2691 if url.is_null() {
2692 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2694 return ctxt;
2695 }
2696
2697 let url_str = unsafe {
2699 if url.is_null() {
2700 String::new()
2701 } else {
2702 let mut len = 0;
2703 while *url.add(len) != 0 {
2704 len += 1;
2705 }
2706 let slice = std::slice::from_raw_parts(url as *const u8, len);
2707 String::from_utf8_lossy(slice).to_string()
2708 }
2709 };
2710
2711 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2714 if !url_str.is_empty() {
2716 let _ = url_str;
2718 }
2719
2720 ctxt
2721}
2722
2723#[no_mangle]
2735pub unsafe extern "C" fn xmlSchemaNewMemParserCtxt(
2736 buffer: *const c_char,
2737 size: c_int,
2738) -> *mut c_void {
2739 if buffer.is_null() || size <= 0 {
2740 return ptr::null_mut();
2741 }
2742
2743 let buf_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, size as usize) };
2745 let xml_str = String::from_utf8_lossy(buf_slice).to_string();
2746
2747 match xsd_parse(&xml_str) {
2748 Ok(schema) => {
2749 let schema_box = Box::new(schema);
2751 Box::into_raw(schema_box) as *mut c_void
2752 }
2753 Err(_) => ptr::null_mut(),
2754 }
2755}
2756
2757#[no_mangle]
2769pub const unsafe extern "C" fn xmlSchemaParse(ctxt: *mut c_void) -> *mut c_void {
2770 if ctxt.is_null() {
2771 return ptr::null_mut();
2772 }
2773
2774 ctxt
2778}
2779
2780#[no_mangle]
2792pub unsafe extern "C" fn xmlSchemaFree(schema: *mut c_void) {
2793 if schema.is_null() {
2794 return;
2795 }
2796 unsafe {
2798 let _ = Box::from_raw(schema as *mut XsdSchema);
2799 }
2800}
2801
2802#[no_mangle]
2817pub unsafe extern "C" fn xmlSchemaValidateDoc(ctxt: *mut c_void, doc: *mut _xmlDoc) -> c_int {
2818 if ctxt.is_null() || doc.is_null() {
2819 return -1;
2820 }
2821
2822 unsafe {
2823 let valid_ctxt = &mut *(ctxt as *mut XsdValidCtxt);
2824 let schema = match &valid_ctxt.schema {
2825 Some(s) => s,
2826 None => return -1,
2827 };
2828
2829 let mut temp_ctxt = XsdValidCtxt::new();
2830 temp_ctxt.schema = Some(schema.clone());
2831
2832 let valid = xsd_validate_doc(schema, doc, &mut temp_ctxt);
2833
2834 if valid {
2835 0
2836 } else {
2837 valid_ctxt.errors = temp_ctxt.errors;
2838 valid_ctxt.nb_errors = temp_ctxt.nb_errors;
2839 temp_ctxt.nb_errors
2840 }
2841 }
2842}
2843
2844#[no_mangle]
2856pub unsafe extern "C" fn xmlSchemaFreeParserCtxt(ctxt: *mut c_void) {
2857 if ctxt.is_null() {
2858 return;
2859 }
2860 unsafe {
2862 let _ = Box::from_raw(ctxt as *mut XsdSchema);
2863 }
2864}
2865
2866#[no_mangle]
2878pub unsafe extern "C" fn xmlSchemaFreeValidCtxt(ctxt: *mut c_void) {
2879 if ctxt.is_null() {
2880 return;
2881 }
2882 unsafe {
2884 let _ = Box::from_raw(ctxt as *mut XsdValidCtxt);
2885 }
2886}
2887
2888#[no_mangle]
2900pub unsafe extern "C" fn xmlSchemaNewValidCtxt(schema: *mut c_void) -> *mut c_void {
2901 let mut ctxt = XsdValidCtxt::new();
2902
2903 if !schema.is_null() {
2904 unsafe {
2906 let schema_ref = &*(schema as *const XsdSchema);
2907 ctxt.schema = Some(schema_ref.clone());
2908 }
2909 }
2910
2911 let boxed = Box::new(ctxt);
2912 Box::into_raw(boxed) as *mut c_void
2913}
2914
2915#[cfg(test)]
2920mod tests {
2921 use super::*;
2922
2923 #[test]
2926 fn test_validate_string() {
2927 assert!(xsd_validate_datatype(
2928 &XsdDatatypeKind::String,
2929 "hello",
2930 &[]
2931 ));
2932 assert!(xsd_validate_datatype(&XsdDatatypeKind::String, "", &[]));
2933 }
2934
2935 #[test]
2936 fn test_validate_boolean() {
2937 assert!(xsd_validate_datatype(
2938 &XsdDatatypeKind::Boolean,
2939 "true",
2940 &[]
2941 ));
2942 assert!(xsd_validate_datatype(
2943 &XsdDatatypeKind::Boolean,
2944 "false",
2945 &[]
2946 ));
2947 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "1", &[]));
2948 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "0", &[]));
2949 assert!(!xsd_validate_datatype(
2950 &XsdDatatypeKind::Boolean,
2951 "yes",
2952 &[]
2953 ));
2954 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Boolean, "no", &[]));
2955 }
2956
2957 #[test]
2958 fn test_validate_integer() {
2959 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "42", &[]));
2960 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "-42", &[]));
2961 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "+42", &[]));
2962 assert!(!xsd_validate_datatype(
2963 &XsdDatatypeKind::Integer,
2964 "12.5",
2965 &[]
2966 ));
2967 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Integer, "", &[]));
2968 assert!(!xsd_validate_datatype(
2969 &XsdDatatypeKind::Integer,
2970 "abc",
2971 &[]
2972 ));
2973 }
2974
2975 #[test]
2976 fn test_validate_decimal() {
2977 assert!(xsd_validate_datatype(&XsdDatatypeKind::Decimal, "42", &[]));
2978 assert!(xsd_validate_datatype(
2979 &XsdDatatypeKind::Decimal,
2980 "12.5",
2981 &[]
2982 ));
2983 assert!(xsd_validate_datatype(
2984 &XsdDatatypeKind::Decimal,
2985 "-3.14",
2986 &[]
2987 ));
2988 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Decimal, "", &[]));
2989 }
2990
2991 #[test]
2992 fn test_validate_float() {
2993 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "3.14", &[]));
2994 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "INF", &[]));
2995 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "-INF", &[]));
2996 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "NaN", &[]));
2997 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Float, "", &[]));
2998 }
2999
3000 #[test]
3001 fn test_validate_positive_integer() {
3002 assert!(xsd_validate_datatype(
3003 &XsdDatatypeKind::PositiveInteger,
3004 "1",
3005 &[]
3006 ));
3007 assert!(xsd_validate_datatype(
3008 &XsdDatatypeKind::PositiveInteger,
3009 "100",
3010 &[]
3011 ));
3012 assert!(!xsd_validate_datatype(
3013 &XsdDatatypeKind::PositiveInteger,
3014 "0",
3015 &[]
3016 ));
3017 assert!(!xsd_validate_datatype(
3018 &XsdDatatypeKind::PositiveInteger,
3019 "-1",
3020 &[]
3021 ));
3022 }
3023
3024 #[test]
3025 fn test_validate_non_negative_integer() {
3026 assert!(xsd_validate_datatype(
3027 &XsdDatatypeKind::NonNegativeInteger,
3028 "0",
3029 &[]
3030 ));
3031 assert!(xsd_validate_datatype(
3032 &XsdDatatypeKind::NonNegativeInteger,
3033 "42",
3034 &[]
3035 ));
3036 assert!(!xsd_validate_datatype(
3037 &XsdDatatypeKind::NonNegativeInteger,
3038 "-1",
3039 &[]
3040 ));
3041 }
3042
3043 #[test]
3044 fn test_validate_int_range() {
3045 assert!(xsd_validate_datatype(
3046 &XsdDatatypeKind::Int,
3047 "2147483647",
3048 &[]
3049 ));
3050 assert!(xsd_validate_datatype(
3051 &XsdDatatypeKind::Int,
3052 "-2147483648",
3053 &[]
3054 ));
3055 assert!(!xsd_validate_datatype(
3056 &XsdDatatypeKind::Int,
3057 "2147483648",
3058 &[]
3059 ));
3060 }
3061
3062 #[test]
3063 fn test_validate_short_range() {
3064 assert!(xsd_validate_datatype(&XsdDatatypeKind::Short, "32767", &[]));
3065 assert!(xsd_validate_datatype(
3066 &XsdDatatypeKind::Short,
3067 "-32768",
3068 &[]
3069 ));
3070 assert!(!xsd_validate_datatype(
3071 &XsdDatatypeKind::Short,
3072 "32768",
3073 &[]
3074 ));
3075 }
3076
3077 #[test]
3078 fn test_validate_byte_range() {
3079 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "127", &[]));
3080 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "-128", &[]));
3081 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Byte, "128", &[]));
3082 }
3083
3084 #[test]
3085 fn test_validate_date_time() {
3086 assert!(xsd_validate_datatype(
3087 &XsdDatatypeKind::DateTime,
3088 "2023-01-15T10:30:00",
3089 &[]
3090 ));
3091 assert!(!xsd_validate_datatype(
3092 &XsdDatatypeKind::DateTime,
3093 "not-a-date",
3094 &[]
3095 ));
3096 }
3097
3098 #[test]
3099 fn test_validate_date() {
3100 assert!(xsd_validate_datatype(
3101 &XsdDatatypeKind::Date,
3102 "2023-01-15",
3103 &[]
3104 ));
3105 assert!(!xsd_validate_datatype(
3106 &XsdDatatypeKind::Date,
3107 "2023/01/15",
3108 &[]
3109 ));
3110 }
3111
3112 #[test]
3113 fn test_validate_time() {
3114 assert!(xsd_validate_datatype(
3115 &XsdDatatypeKind::Time,
3116 "10:30:00",
3117 &[]
3118 ));
3119 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Time, "10:30", &[]));
3120 }
3121
3122 #[test]
3123 fn test_validate_hex_binary() {
3124 assert!(xsd_validate_datatype(
3125 &XsdDatatypeKind::HexBinary,
3126 "0FA1",
3127 &[]
3128 ));
3129 assert!(xsd_validate_datatype(&XsdDatatypeKind::HexBinary, "", &[]));
3130 assert!(!xsd_validate_datatype(
3131 &XsdDatatypeKind::HexBinary,
3132 "0FG1",
3133 &[]
3134 ));
3135 assert!(!xsd_validate_datatype(
3136 &XsdDatatypeKind::HexBinary,
3137 "0FA",
3138 &[]
3139 ));
3140 }
3141
3142 #[test]
3143 fn test_validate_base64() {
3144 assert!(xsd_validate_datatype(
3145 &XsdDatatypeKind::Base64Binary,
3146 "SGVsbG8=",
3147 &[]
3148 ));
3149 assert!(xsd_validate_datatype(
3150 &XsdDatatypeKind::Base64Binary,
3151 "",
3152 &[]
3153 ));
3154 assert!(!xsd_validate_datatype(
3155 &XsdDatatypeKind::Base64Binary,
3156 "Hello World!",
3157 &[]
3158 ));
3159 }
3160
3161 #[test]
3162 fn test_validate_ncname() {
3163 assert!(xsd_validate_datatype(
3164 &XsdDatatypeKind::NCName,
3165 "myElement",
3166 &[]
3167 ));
3168 assert!(xsd_validate_datatype(&XsdDatatypeKind::NCName, "_foo", &[]));
3169 assert!(!xsd_validate_datatype(
3170 &XsdDatatypeKind::NCName,
3171 "123abc",
3172 &[]
3173 ));
3174 assert!(!xsd_validate_datatype(&XsdDatatypeKind::NCName, "", &[]));
3175 }
3176
3177 #[test]
3178 fn test_validate_qname() {
3179 assert!(xsd_validate_datatype(
3180 &XsdDatatypeKind::QName,
3181 "ns:local",
3182 &[]
3183 ));
3184 assert!(xsd_validate_datatype(&XsdDatatypeKind::QName, "local", &[]));
3185 assert!(!xsd_validate_datatype(&XsdDatatypeKind::QName, "", &[]));
3186 }
3187
3188 #[test]
3189 fn test_validate_token() {
3190 assert!(xsd_validate_datatype(&XsdDatatypeKind::Token, "hello", &[]));
3191 assert!(!xsd_validate_datatype(
3192 &XsdDatatypeKind::Token,
3193 " hello",
3194 &[]
3195 ));
3196 assert!(!xsd_validate_datatype(
3197 &XsdDatatypeKind::Token,
3198 "hello ",
3199 &[]
3200 ));
3201 assert!(!xsd_validate_datatype(
3202 &XsdDatatypeKind::Token,
3203 "hello world",
3204 &[]
3205 ));
3206 assert!(!xsd_validate_datatype(
3207 &XsdDatatypeKind::Token,
3208 "hello\tworld",
3209 &[]
3210 ));
3211 }
3212
3213 #[test]
3214 fn test_validate_language() {
3215 assert!(xsd_validate_datatype(&XsdDatatypeKind::Language, "en", &[]));
3216 assert!(xsd_validate_datatype(
3217 &XsdDatatypeKind::Language,
3218 "en-US",
3219 &[]
3220 ));
3221 assert!(xsd_validate_datatype(
3222 &XsdDatatypeKind::Language,
3223 "zh-CN",
3224 &[]
3225 ));
3226 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Language, "", &[]));
3227 assert!(!xsd_validate_datatype(
3228 &XsdDatatypeKind::Language,
3229 "123",
3230 &[]
3231 ));
3232 }
3233
3234 #[test]
3235 fn test_validate_name() {
3236 assert!(xsd_validate_datatype(
3237 &XsdDatatypeKind::Name,
3238 "myElement",
3239 &[]
3240 ));
3241 assert!(xsd_validate_datatype(
3242 &XsdDatatypeKind::Name,
3243 "ns:local",
3244 &[]
3245 ));
3246 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Name, "", &[]));
3247 }
3248
3249 #[test]
3250 fn test_validate_nmtoken() {
3251 assert!(xsd_validate_datatype(
3252 &XsdDatatypeKind::Nmtoken,
3253 "token123",
3254 &[]
3255 ));
3256 assert!(xsd_validate_datatype(
3257 &XsdDatatypeKind::Nmtoken,
3258 "123token",
3259 &[]
3260 ));
3261 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Nmtoken, "", &[]));
3262 }
3263
3264 #[test]
3265 fn test_validate_duration() {
3266 assert!(xsd_validate_datatype(
3267 &XsdDatatypeKind::Duration,
3268 "P1Y2M3DT4H5M6S",
3269 &[]
3270 ));
3271 assert!(xsd_validate_datatype(
3272 &XsdDatatypeKind::Duration,
3273 "P1Y",
3274 &[]
3275 ));
3276 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Duration, "", &[]));
3277 }
3278
3279 #[test]
3280 fn test_validate_g_year() {
3281 assert!(xsd_validate_datatype(&XsdDatatypeKind::GYear, "2023", &[]));
3282 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GYear, "", &[]));
3283 }
3284
3285 #[test]
3286 fn test_validate_g_month() {
3287 assert!(xsd_validate_datatype(&XsdDatatypeKind::GMonth, "--05", &[]));
3288 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GMonth, "", &[]));
3289 }
3290
3291 #[test]
3292 fn test_validate_g_day() {
3293 assert!(xsd_validate_datatype(&XsdDatatypeKind::GDay, "---15", &[]));
3294 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GDay, "", &[]));
3295 }
3296
3297 #[test]
3300 fn test_facet_min_length() {
3301 let facets = vec![(XsdDatatypeKind::FacetMinLength, "3".to_string())];
3302 assert!(xsd_validate_datatype(
3303 &XsdDatatypeKind::String,
3304 "hello",
3305 &facets
3306 ));
3307 assert!(xsd_validate_datatype(
3308 &XsdDatatypeKind::String,
3309 "abc",
3310 &facets
3311 ));
3312 assert!(!xsd_validate_datatype(
3313 &XsdDatatypeKind::String,
3314 "ab",
3315 &facets
3316 ));
3317 }
3318
3319 #[test]
3320 fn test_facet_max_length() {
3321 let facets = vec![(XsdDatatypeKind::FacetMaxLength, "3".to_string())];
3322 assert!(xsd_validate_datatype(
3323 &XsdDatatypeKind::String,
3324 "ab",
3325 &facets
3326 ));
3327 assert!(xsd_validate_datatype(
3328 &XsdDatatypeKind::String,
3329 "abc",
3330 &facets
3331 ));
3332 assert!(!xsd_validate_datatype(
3333 &XsdDatatypeKind::String,
3334 "abcd",
3335 &facets
3336 ));
3337 }
3338
3339 #[test]
3340 fn test_facet_length() {
3341 let facets = vec![(XsdDatatypeKind::FacetLength, "3".to_string())];
3342 assert!(xsd_validate_datatype(
3343 &XsdDatatypeKind::String,
3344 "abc",
3345 &facets
3346 ));
3347 assert!(!xsd_validate_datatype(
3348 &XsdDatatypeKind::String,
3349 "ab",
3350 &facets
3351 ));
3352 assert!(!xsd_validate_datatype(
3353 &XsdDatatypeKind::String,
3354 "abcd",
3355 &facets
3356 ));
3357 }
3358
3359 #[test]
3360 fn test_facet_min_inclusive() {
3361 let facets = vec![(XsdDatatypeKind::FacetMinInclusive, "5".to_string())];
3362 assert!(xsd_validate_datatype(
3363 &XsdDatatypeKind::Integer,
3364 "5",
3365 &facets
3366 ));
3367 assert!(xsd_validate_datatype(
3368 &XsdDatatypeKind::Integer,
3369 "10",
3370 &facets
3371 ));
3372 assert!(!xsd_validate_datatype(
3373 &XsdDatatypeKind::Integer,
3374 "3",
3375 &facets
3376 ));
3377 }
3378
3379 #[test]
3380 fn test_facet_max_inclusive() {
3381 let facets = vec![(XsdDatatypeKind::FacetMaxInclusive, "10".to_string())];
3382 assert!(xsd_validate_datatype(
3383 &XsdDatatypeKind::Integer,
3384 "10",
3385 &facets
3386 ));
3387 assert!(xsd_validate_datatype(
3388 &XsdDatatypeKind::Integer,
3389 "5",
3390 &facets
3391 ));
3392 assert!(!xsd_validate_datatype(
3393 &XsdDatatypeKind::Integer,
3394 "15",
3395 &facets
3396 ));
3397 }
3398
3399 #[test]
3400 fn test_facet_pattern_digits() {
3401 let facets = vec![(XsdDatatypeKind::FacetPattern, r"\d+".to_string())];
3402 assert!(xsd_validate_datatype(
3403 &XsdDatatypeKind::String,
3404 "123",
3405 &facets
3406 ));
3407 assert!(!xsd_validate_datatype(
3408 &XsdDatatypeKind::String,
3409 "abc",
3410 &facets
3411 ));
3412 }
3413
3414 #[test]
3415 fn test_facet_pattern_alpha() {
3416 let facets = vec![(XsdDatatypeKind::FacetPattern, r"[a-zA-Z]+".to_string())];
3417 assert!(xsd_validate_datatype(
3418 &XsdDatatypeKind::String,
3419 "hello",
3420 &facets
3421 ));
3422 assert!(!xsd_validate_datatype(
3423 &XsdDatatypeKind::String,
3424 "123",
3425 &facets
3426 ));
3427 }
3428
3429 #[test]
3432 fn test_parse_empty_schema() {
3433 let schema_xml = r#"<?xml version="1.0"?>
3434 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3435 </xs:schema>"#;
3436
3437 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3438 assert!(schema.components.is_empty());
3439 }
3440
3441 #[test]
3442 fn test_parse_schema_with_target_namespace() {
3443 let schema_xml = r#"<?xml version="1.0"?>
3444 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
3445 targetNamespace="http://example.com/ns">
3446 </xs:schema>"#;
3447
3448 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3449 assert_eq!(
3450 schema.target_namespace,
3451 Some("http://example.com/ns".to_string())
3452 );
3453 }
3454
3455 #[test]
3456 fn test_parse_simple_element() {
3457 let schema_xml = r#"<?xml version="1.0"?>
3458 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3459 <xs:element name="name" type="xs:string"/>
3460 </xs:schema>"#;
3461
3462 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3463 assert_eq!(schema.components.len(), 1);
3464 assert_eq!(
3465 schema.components[0].component_type,
3466 XsdComponentType::Element
3467 );
3468 assert_eq!(schema.components[0].name, Some("name".to_string()));
3469 assert_eq!(schema.components[0].datatype, Some(XsdDatatypeKind::String));
3470 }
3471
3472 #[test]
3473 fn test_parse_integer_element() {
3474 let schema_xml = r#"<?xml version="1.0"?>
3475 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3476 <xs:element name="age" type="xs:integer"/>
3477 </xs:schema>"#;
3478
3479 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3480 assert_eq!(schema.components.len(), 1);
3481 assert_eq!(schema.components[0].name, Some("age".to_string()));
3482 assert_eq!(
3483 schema.components[0].datatype,
3484 Some(XsdDatatypeKind::Integer)
3485 );
3486 }
3487
3488 #[test]
3489 fn test_parse_element_with_attributes() {
3490 let schema_xml = r#"<?xml version="1.0"?>
3491 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3492 <xs:element name="product">
3493 <xs:complexType>
3494 <xs:sequence>
3495 <xs:element name="name" type="xs:string"/>
3496 <xs:element name="price" type="xs:decimal"/>
3497 </xs:sequence>
3498 <xs:attribute name="id" type="xs:integer" use="required"/>
3499 </xs:complexType>
3500 </xs:element>
3501 </xs:schema>"#;
3502
3503 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3504 assert_eq!(schema.components.len(), 1);
3505 assert_eq!(schema.components[0].name, Some("product".to_string()));
3506
3507 let ct = &schema.components[0].children;
3509 let complex_type = ct
3510 .iter()
3511 .find(|c| c.component_type == XsdComponentType::ComplexType);
3512 assert!(complex_type.is_some());
3513 if let Some(ctc) = complex_type {
3514 assert_eq!(ctc.attributes.len(), 1);
3515 assert_eq!(ctc.attributes[0].name, Some("id".to_string()));
3516 assert_eq!(ctc.attributes[0].datatype, Some(XsdDatatypeKind::Integer));
3517 }
3518 }
3519
3520 #[test]
3521 fn test_parse_complex_type_with_sequence() {
3522 let schema_xml = r#"<?xml version="1.0"?>
3523 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3524 <xs:complexType name="AddressType">
3525 <xs:sequence>
3526 <xs:element name="street" type="xs:string"/>
3527 <xs:element name="city" type="xs:string"/>
3528 <xs:element name="zip" type="xs:string"/>
3529 </xs:sequence>
3530 </xs:complexType>
3531 </xs:schema>"#;
3532
3533 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3534 assert_eq!(schema.components.len(), 1);
3535 assert_eq!(
3536 schema.components[0].component_type,
3537 XsdComponentType::ComplexType
3538 );
3539 assert_eq!(schema.components[0].name, Some("AddressType".to_string()));
3540 }
3541
3542 #[test]
3543 fn test_parse_restriction() {
3544 let schema_xml = r#"<?xml version="1.0"?>
3545 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3546 <xs:simpleType name="AgeType">
3547 <xs:restriction base="xs:integer">
3548 <xs:minInclusive value="0"/>
3549 <xs:maxInclusive value="150"/>
3550 </xs:restriction>
3551 </xs:simpleType>
3552 </xs:schema>"#;
3553
3554 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3555 assert_eq!(schema.components.len(), 1);
3556 assert_eq!(
3557 schema.components[0].component_type,
3558 XsdComponentType::SimpleType
3559 );
3560
3561 let st = &schema.components[0];
3563 assert_eq!(st.datatype, Some(XsdDatatypeKind::Integer));
3564 assert!(!st.facets.is_empty());
3565 }
3566
3567 #[test]
3568 fn test_parse_enumeration() {
3569 let schema_xml = r#"<?xml version="1.0"?>
3570 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3571 <xs:simpleType name="ColorType">
3572 <xs:restriction base="xs:string">
3573 <xs:enumeration value="red"/>
3574 <xs:enumeration value="green"/>
3575 <xs:enumeration value="blue"/>
3576 </xs:restriction>
3577 </xs:simpleType>
3578 </xs:schema>"#;
3579
3580 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3581 assert_eq!(schema.components.len(), 1);
3582 assert_eq!(schema.components[0].name, Some("ColorType".to_string()));
3583 }
3584
3585 #[test]
3586 fn test_parse_min_max_occurs() {
3587 let schema_xml = r#"<?xml version="1.0"?>
3588 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3589 <xs:element name="items">
3590 <xs:complexType>
3591 <xs:sequence>
3592 <xs:element name="item" type="xs:string"
3593 minOccurs="0" maxOccurs="unbounded"/>
3594 </xs:sequence>
3595 </xs:complexType>
3596 </xs:element>
3597 </xs:schema>"#;
3598
3599 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3600 assert_eq!(schema.components.len(), 1);
3601
3602 let elem = &schema.components[0];
3604 let ct = elem
3605 .children
3606 .iter()
3607 .find(|c| c.component_type == XsdComponentType::ComplexType);
3608 assert!(ct.is_some());
3609 if let Some(ctc) = ct {
3610 let seq = ctc
3611 .children
3612 .iter()
3613 .find(|c| c.component_type == XsdComponentType::Sequence);
3614 assert!(seq.is_some());
3615 if let Some(seqc) = seq {
3616 assert!(!seqc.children.is_empty());
3617 let item = &seqc.children[0];
3618 assert_eq!(item.min_occurs, 0);
3619 assert_eq!(item.max_occurs, -1);
3620 }
3621 }
3622 }
3623
3624 #[test]
3625 fn test_parse_attribute_default() {
3626 let schema_xml = r#"<?xml version="1.0"?>
3627 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3628 <xs:element name="book">
3629 <xs:complexType>
3630 <xs:sequence>
3631 <xs:element name="title" type="xs:string"/>
3632 </xs:sequence>
3633 <xs:attribute name="lang" type="xs:string" default="en"/>
3634 <xs:attribute name="id" type="xs:integer" use="required"/>
3635 </xs:complexType>
3636 </xs:element>
3637 </xs:schema>"#;
3638
3639 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3640 let elem = &schema.components[0];
3641 let ct = elem
3642 .children
3643 .iter()
3644 .find(|c| c.component_type == XsdComponentType::ComplexType);
3645 assert!(ct.is_some());
3646 if let Some(ctc) = ct {
3647 let lang_attr = ctc
3648 .attributes
3649 .iter()
3650 .find(|a| a.name.as_deref() == Some("lang"));
3651 assert!(lang_attr.is_some());
3652 if let Some(la) = lang_attr {
3653 assert_eq!(la.min_occurs, 0); }
3655
3656 let id_attr = ctc
3657 .attributes
3658 .iter()
3659 .find(|a| a.name.as_deref() == Some("id"));
3660 assert!(id_attr.is_some());
3661 }
3662 }
3663
3664 #[test]
3665 fn test_parse_element_with_ref() {
3666 let schema_xml = r#"<?xml version="1.0"?>
3667 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3668 <xs:element name="root">
3669 <xs:complexType>
3670 <xs:sequence>
3671 <xs:element ref="child" minOccurs="0"/>
3672 </xs:sequence>
3673 </xs:complexType>
3674 </xs:element>
3675 <xs:element name="child" type="xs:string"/>
3676 </xs:schema>"#;
3677
3678 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3679 assert_eq!(schema.components.len(), 2);
3680 let root = &schema.components[0];
3682 let ct = root
3683 .children
3684 .iter()
3685 .find(|c| c.component_type == XsdComponentType::ComplexType);
3686 assert!(ct.is_some());
3687 if let Some(ctc) = ct {
3688 let seq = ctc
3689 .children
3690 .iter()
3691 .find(|c| c.component_type == XsdComponentType::Sequence);
3692 assert!(seq.is_some());
3693 if let Some(seqc) = seq {
3694 assert!(!seqc.children.is_empty());
3695 let ref_elem = &seqc.children[0];
3696 assert_eq!(ref_elem.ref_name, Some("child".to_string()));
3697 }
3698 }
3699 }
3700
3701 #[test]
3704 fn test_validate_simple_element() {
3705 let schema_xml = r#"<?xml version="1.0"?>
3706 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3707 <xs:element name="name" type="xs:string"/>
3708 </xs:schema>"#;
3709
3710 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3711
3712 let doc = r#"<?xml version="1.0"?>
3713 <name>John Doe</name>"#;
3714
3715 assert!(xsd_validate(&schema, doc).is_ok());
3716 }
3717
3718 #[test]
3719 fn test_validate_integer_element() {
3720 let schema_xml = r#"<?xml version="1.0"?>
3721 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3722 <xs:element name="age" type="xs:integer"/>
3723 </xs:schema>"#;
3724
3725 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3726
3727 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3728 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>not-a-number</age>"#).is_err());
3729 }
3730
3731 #[test]
3732 fn test_validate_complex_element() {
3733 let schema_xml = r#"<?xml version="1.0"?>
3734 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3735 <xs:element name="product">
3736 <xs:complexType>
3737 <xs:sequence>
3738 <xs:element name="name" type="xs:string"/>
3739 <xs:element name="price" type="xs:decimal"/>
3740 </xs:sequence>
3741 <xs:attribute name="id" type="xs:integer" use="required"/>
3742 </xs:complexType>
3743 </xs:element>
3744 </xs:schema>"#;
3745
3746 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3747
3748 let valid_doc = r#"<?xml version="1.0"?>
3749 <product id="123">
3750 <name>Widget</name>
3751 <price>9.99</price>
3752 </product>"#;
3753
3754 assert!(xsd_validate(&schema, valid_doc).is_ok());
3755 }
3756
3757 #[test]
3758 fn test_validate_missing_required_attribute() {
3759 let schema_xml = r#"<?xml version="1.0"?>
3760 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3761 <xs:element name="product">
3762 <xs:complexType>
3763 <xs:sequence>
3764 <xs:element name="name" type="xs:string"/>
3765 </xs:sequence>
3766 <xs:attribute name="id" type="xs:integer" use="required"/>
3767 </xs:complexType>
3768 </xs:element>
3769 </xs:schema>"#;
3770
3771 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3772
3773 let invalid_doc = r#"<?xml version="1.0"?>
3774 <product>
3775 <name>Widget</name>
3776 </product>"#;
3777
3778 assert!(xsd_validate(&schema, invalid_doc).is_err());
3779 }
3780
3781 #[test]
3782 fn test_validate_enumeration_facet() {
3783 let schema_xml = r#"<?xml version="1.0"?>
3784 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3785 <xs:element name="color">
3786 <xs:simpleType>
3787 <xs:restriction base="xs:string">
3788 <xs:enumeration value="red"/>
3789 <xs:enumeration value="green"/>
3790 <xs:enumeration value="blue"/>
3791 </xs:restriction>
3792 </xs:simpleType>
3793 </xs:element>
3794 </xs:schema>"#;
3795
3796 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3797
3798 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><color>red</color>"#).is_ok());
3801 }
3802
3803 #[test]
3804 fn test_validate_boolean_element() {
3805 let schema_xml = r#"<?xml version="1.0"?>
3806 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3807 <xs:element name="active" type="xs:boolean"/>
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"?><active>true</active>"#).is_ok());
3813 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>false</active>"#).is_ok());
3814 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>1</active>"#).is_ok());
3815 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>yes</active>"#).is_err());
3816 }
3817
3818 #[test]
3819 fn test_validate_element_with_range_constraint() {
3820 let schema_xml = r#"<?xml version="1.0"?>
3821 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3822 <xs:element name="age">
3823 <xs:simpleType>
3824 <xs:restriction base="xs:integer">
3825 <xs:minInclusive value="0"/>
3826 <xs:maxInclusive value="150"/>
3827 </xs:restriction>
3828 </xs:simpleType>
3829 </xs:element>
3830 </xs:schema>"#;
3831
3832 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3833
3834 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3835 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>0</age>"#).is_ok());
3836 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>150</age>"#).is_ok());
3837 }
3839
3840 #[test]
3841 fn test_validate_optional_element() {
3842 let schema_xml = r#"<?xml version="1.0"?>
3843 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3844 <xs:element name="person">
3845 <xs:complexType>
3846 <xs:sequence>
3847 <xs:element name="name" type="xs:string"/>
3848 <xs:element name="nickname" type="xs:string" minOccurs="0"/>
3849 </xs:sequence>
3850 </xs:complexType>
3851 </xs:element>
3852 </xs:schema>"#;
3853
3854 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3855
3856 let doc_with_nick = r#"<?xml version="1.0"?>
3857 <person>
3858 <name>John</name>
3859 <nickname>Johnny</nickname>
3860 </person>"#;
3861
3862 let doc_without_nick = r#"<?xml version="1.0"?>
3863 <person>
3864 <name>John</name>
3865 </person>"#;
3866
3867 assert!(xsd_validate(&schema, doc_with_nick).is_ok());
3868 assert!(xsd_validate(&schema, doc_without_nick).is_ok());
3869 }
3870
3871 #[test]
3872 fn test_validate_unbounded_element() {
3873 let schema_xml = r#"<?xml version="1.0"?>
3874 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3875 <xs:element name="items">
3876 <xs:complexType>
3877 <xs:sequence>
3878 <xs:element name="item" type="xs:string"
3879 minOccurs="0" maxOccurs="unbounded"/>
3880 </xs:sequence>
3881 </xs:complexType>
3882 </xs:element>
3883 </xs:schema>"#;
3884
3885 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3886
3887 let doc = r#"<?xml version="1.0"?>
3888 <items>
3889 <item>one</item>
3890 <item>two</item>
3891 <item>three</item>
3892 </items>"#;
3893
3894 assert!(xsd_validate(&schema, doc).is_ok());
3895 }
3896
3897 #[test]
3898 fn test_validate_date_element() {
3899 let schema_xml = r#"<?xml version="1.0"?>
3900 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3901 <xs:element name="birthDate" type="xs:date"/>
3902 </xs:schema>"#;
3903
3904 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3905
3906 assert!(xsd_validate(
3907 &schema,
3908 r#"<?xml version="1.0"?><birthDate>1990-01-15</birthDate>"#
3909 )
3910 .is_ok());
3911 assert!(xsd_validate(
3912 &schema,
3913 r#"<?xml version="1.0"?><birthDate>not-a-date</birthDate>"#
3914 )
3915 .is_err());
3916 }
3917
3918 #[test]
3919 fn test_validate_choice() {
3920 let schema_xml = r#"<?xml version="1.0"?>
3921 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3922 <xs:element name="contact">
3923 <xs:complexType>
3924 <xs:choice>
3925 <xs:element name="email" type="xs:string"/>
3926 <xs:element name="phone" type="xs:string"/>
3927 </xs:choice>
3928 </xs:complexType>
3929 </xs:element>
3930 </xs:schema>"#;
3931
3932 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3933
3934 assert!(xsd_validate(
3935 &schema,
3936 r#"<?xml version="1.0"?><contact><email>a@b.com</email></contact>"#
3937 )
3938 .is_ok());
3939 assert!(xsd_validate(
3940 &schema,
3941 r#"<?xml version="1.0"?><contact><phone>555-1234</phone></contact>"#
3942 )
3943 .is_ok());
3944 }
3945
3946 #[test]
3947 fn test_validate_positive_integer_constraint() {
3948 let schema_xml = r#"<?xml version="1.0"?>
3949 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3950 <xs:element name="quantity" type="xs:positiveInteger"/>
3951 </xs:schema>"#;
3952
3953 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3954
3955 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>1</quantity>"#).is_ok());
3956 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>0</quantity>"#).is_err());
3957 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>-1</quantity>"#).is_err());
3958 }
3959
3960 #[test]
3963 fn test_xml_schema_new_mem_parser_ctxt() {
3964 let schema_xml = r#"<?xml version="1.0"?>
3965 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3966 <xs:element name="name" type="xs:string"/>
3967 </xs:schema>"#;
3968
3969 let ctxt = unsafe {
3970 xmlSchemaNewMemParserCtxt(
3971 schema_xml.as_ptr() as *const c_char,
3972 schema_xml.len() as c_int,
3973 )
3974 };
3975 assert!(!ctxt.is_null());
3976
3977 let schema = unsafe { xmlSchemaParse(ctxt) };
3978 assert!(!schema.is_null());
3979
3980 unsafe {
3981 xmlSchemaFree(schema);
3982 }
3983 }
3984
3985 #[test]
3986 fn test_xml_schema_validate_doc() {
3987 let schema_xml = r#"<?xml version="1.0"?>
3988 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3989 <xs:element name="name" type="xs:string"/>
3990 </xs:schema>"#;
3991
3992 let doc_xml = r#"<?xml version="1.0"?>
3993 <name>John Doe</name>"#;
3994
3995 let ctxt = unsafe {
3996 xmlSchemaNewMemParserCtxt(
3997 schema_xml.as_ptr() as *const c_char,
3998 schema_xml.len() as c_int,
3999 )
4000 };
4001 let schema = unsafe { xmlSchemaParse(ctxt) };
4002 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
4003
4004 let doc = unsafe {
4005 crate::abi::exports_xml2::xmlReadMemory(
4006 doc_xml.as_ptr() as *const c_char,
4007 doc_xml.len() as c_int,
4008 c"test.xml".as_ptr() as *const c_char,
4009 ptr::null(),
4010 0,
4011 )
4012 };
4013
4014 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
4015 assert_eq!(result, 0);
4016
4017 unsafe {
4018 xmlSchemaFreeValidCtxt(valid_ctxt);
4019 xmlSchemaFree(schema);
4020 crate::abi::exports_xml2::xmlFreeDoc(doc);
4021 }
4022 }
4023
4024 #[test]
4025 fn test_xml_schema_validate_invalid_doc() {
4026 let schema_xml = r#"<?xml version="1.0"?>
4027 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4028 <xs:element name="age" type="xs:integer"/>
4029 </xs:schema>"#;
4030
4031 let doc_xml = r#"<?xml version="1.0"?>
4032 <age>not-a-number</age>"#;
4033
4034 let ctxt = unsafe {
4035 xmlSchemaNewMemParserCtxt(
4036 schema_xml.as_ptr() as *const c_char,
4037 schema_xml.len() as c_int,
4038 )
4039 };
4040 let schema = unsafe { xmlSchemaParse(ctxt) };
4041 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
4042
4043 let doc = unsafe {
4044 crate::abi::exports_xml2::xmlReadMemory(
4045 doc_xml.as_ptr() as *const c_char,
4046 doc_xml.len() as c_int,
4047 c"test.xml".as_ptr() as *const c_char,
4048 ptr::null(),
4049 0,
4050 )
4051 };
4052
4053 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
4054 assert_ne!(result, 0); unsafe {
4057 xmlSchemaFreeValidCtxt(valid_ctxt);
4058 xmlSchemaFree(schema);
4059 crate::abi::exports_xml2::xmlFreeDoc(doc);
4060 }
4061 }
4062
4063 #[test]
4064 fn test_xml_schema_new_valid_ctxt_null() {
4065 let ctxt = unsafe { xmlSchemaNewValidCtxt(ptr::null_mut()) };
4066 assert!(!ctxt.is_null());
4067 unsafe { xmlSchemaFreeValidCtxt(ctxt) };
4068 }
4069
4070 #[test]
4071 fn test_xml_schema_free_null() {
4072 unsafe {
4073 xmlSchemaFree(ptr::null_mut());
4074 xmlSchemaFreeParserCtxt(ptr::null_mut());
4075 xmlSchemaFreeValidCtxt(ptr::null_mut());
4076 }
4077 }
4078
4079 #[test]
4080 fn test_xml_schema_new_parser_ctxt_null() {
4081 let ctxt = unsafe { xmlSchemaNewParserCtxt(ptr::null()) };
4082 assert!(!ctxt.is_null());
4083 unsafe {
4085 allocator::xmlFreeImpl(ctxt);
4086 }
4087 }
4088
4089 #[test]
4090 fn test_datatype_parse_kind() {
4091 assert_eq!(
4092 parse_datatype_kind("xs:string"),
4093 Some(XsdDatatypeKind::String)
4094 );
4095 assert_eq!(parse_datatype_kind("string"), Some(XsdDatatypeKind::String));
4096 assert_eq!(
4097 parse_datatype_kind("xs:integer"),
4098 Some(XsdDatatypeKind::Integer)
4099 );
4100 assert_eq!(
4101 parse_datatype_kind("xs:boolean"),
4102 Some(XsdDatatypeKind::Boolean)
4103 );
4104 assert_eq!(
4105 parse_datatype_kind("xs:decimal"),
4106 Some(XsdDatatypeKind::Decimal)
4107 );
4108 assert_eq!(
4109 parse_datatype_kind("xs:float"),
4110 Some(XsdDatatypeKind::Float)
4111 );
4112 assert_eq!(
4113 parse_datatype_kind("xs:double"),
4114 Some(XsdDatatypeKind::Double)
4115 );
4116 assert_eq!(parse_datatype_kind("xs:date"), Some(XsdDatatypeKind::Date));
4117 assert_eq!(
4118 parse_datatype_kind("xs:dateTime"),
4119 Some(XsdDatatypeKind::DateTime)
4120 );
4121 assert_eq!(parse_datatype_kind("xs:time"), Some(XsdDatatypeKind::Time));
4122 assert_eq!(
4123 parse_datatype_kind("xs:hexBinary"),
4124 Some(XsdDatatypeKind::HexBinary)
4125 );
4126 assert_eq!(
4127 parse_datatype_kind("xs:base64Binary"),
4128 Some(XsdDatatypeKind::Base64Binary)
4129 );
4130 assert_eq!(
4131 parse_datatype_kind("xs:anyURI"),
4132 Some(XsdDatatypeKind::AnyURI)
4133 );
4134 assert_eq!(
4135 parse_datatype_kind("xs:QName"),
4136 Some(XsdDatatypeKind::QName)
4137 );
4138 assert_eq!(
4139 parse_datatype_kind("xs:normalizedString"),
4140 Some(XsdDatatypeKind::NormalizedString)
4141 );
4142 assert_eq!(
4143 parse_datatype_kind("xs:token"),
4144 Some(XsdDatatypeKind::Token)
4145 );
4146 assert_eq!(
4147 parse_datatype_kind("xs:language"),
4148 Some(XsdDatatypeKind::Language)
4149 );
4150 assert_eq!(parse_datatype_kind("xs:Name"), Some(XsdDatatypeKind::Name));
4151 assert_eq!(
4152 parse_datatype_kind("xs:NCName"),
4153 Some(XsdDatatypeKind::NCName)
4154 );
4155 assert_eq!(parse_datatype_kind("xs:ID"), Some(XsdDatatypeKind::Id));
4156 assert_eq!(
4157 parse_datatype_kind("xs:IDREF"),
4158 Some(XsdDatatypeKind::Idref)
4159 );
4160 assert_eq!(
4161 parse_datatype_kind("xs:integer"),
4162 Some(XsdDatatypeKind::Integer)
4163 );
4164 assert_eq!(parse_datatype_kind("xs:long"), Some(XsdDatatypeKind::Long));
4165 assert_eq!(parse_datatype_kind("xs:int"), Some(XsdDatatypeKind::Int));
4166 assert_eq!(
4167 parse_datatype_kind("xs:short"),
4168 Some(XsdDatatypeKind::Short)
4169 );
4170 assert_eq!(parse_datatype_kind("xs:byte"), Some(XsdDatatypeKind::Byte));
4171 assert_eq!(
4172 parse_datatype_kind("xs:positiveInteger"),
4173 Some(XsdDatatypeKind::PositiveInteger)
4174 );
4175 assert_eq!(
4176 parse_datatype_kind("xs:negativeInteger"),
4177 Some(XsdDatatypeKind::NegativeInteger)
4178 );
4179 assert_eq!(parse_datatype_kind("unknown"), None);
4180 }
4181}