1use core::ffi::c_void;
71use core::ptr;
72use std::os::raw::{c_char, c_int};
73
74use crate::abi::structs::*;
75use crate::abi::types::xmlElementType::*;
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum XsdComponentType {
89 Schema,
92 Element,
94 Attribute,
96 ComplexType,
98 SimpleType,
100 SimpleContent,
102 ComplexContent,
104 Sequence,
106 Choice,
108 All,
110 Restriction,
112 Extension,
114 List,
116 Union,
118 Annotation,
120 Any,
122 AnyAttribute,
124 Group,
126 AttributeGroup,
128 Notation,
130 Unique,
132 Key,
134 KeyRef,
136 Selector,
138 Field,
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
153pub enum XsdDatatypeKind {
154 String,
157 Boolean,
159 Decimal,
162 Float,
165 Double,
168 Duration,
171 DateTime,
173 Time,
175 Date,
177 GYearMonth,
179 GYear,
181 GMonthDay,
183 GDay,
185 GMonth,
187 HexBinary,
190 Base64Binary,
192 AnyURI,
194 QName,
196 Notation,
199 NormalizedString,
203 Token,
206 Language,
209 Nmtoken,
211 Nmtokens,
213 Name,
215 NCName,
217 Id,
219 Idref,
221 Idrefs,
223 Entity,
225 Entities,
227 Integer,
230 NonPositiveInteger,
232 NegativeInteger,
234 Long,
236 Int,
238 Short,
240 Byte,
242 NonNegativeInteger,
244 UnsignedLong,
246 UnsignedInt,
248 UnsignedShort,
250 UnsignedByte,
252 PositiveInteger,
254 FacetPattern,
257 FacetEnumeration,
260 FacetMinInclusive,
262 FacetMaxInclusive,
264 FacetMinExclusive,
266 FacetMaxExclusive,
268 FacetMinLength,
270 FacetMaxLength,
272 FacetLength,
274 FacetWhiteSpace,
277 FacetFractionDigits,
280 FacetTotalDigits,
282}
283
284#[derive(Debug, Clone)]
293pub struct XsdComponent {
294 pub component_type: XsdComponentType,
296 pub name: Option<String>,
299 pub target_namespace: Option<String>,
301 pub children: Vec<XsdComponent>,
303 pub attributes: Vec<XsdComponent>,
305 pub datatype: Option<XsdDatatypeKind>,
308 pub facets: Vec<(XsdDatatypeKind, String)>,
310 pub base: Option<String>,
313 pub min_occurs: i32,
316 pub max_occurs: i32,
318 pub ref_name: Option<String>,
321 pub substitution_group: Option<String>,
323 pub is_abstract: bool,
325 pub is_final: bool,
327 pub block: Vec<String>,
329 pub mixed: bool,
331 pub form: Option<String>,
334 pub default_value: Option<String>,
339 pub fixed_value: Option<String>,
342}
343
344impl XsdComponent {
345 pub const fn new(component_type: XsdComponentType) -> Self {
349 Self {
350 component_type,
351 name: None,
352 target_namespace: None,
353 children: Vec::new(),
354 attributes: Vec::new(),
355 datatype: None,
356 facets: Vec::new(),
357 base: None,
358 min_occurs: 1,
359 max_occurs: 1,
360 ref_name: None,
361 substitution_group: None,
362 is_abstract: false,
363 is_final: false,
364 block: Vec::new(),
365 mixed: false,
366 form: None,
367 default_value: None,
368 fixed_value: None,
369 }
370 }
371}
372
373#[derive(Debug, Clone)]
381pub struct XsdSchema {
382 pub components: Vec<XsdComponent>,
384 pub target_namespace: Option<String>,
386 pub element_form_default: Option<String>,
388 pub attribute_form_default: Option<String>,
390 pub errors: Vec<String>,
392}
393
394impl XsdSchema {
395 pub const fn new() -> Self {
397 Self {
398 components: Vec::new(),
399 target_namespace: None,
400 element_form_default: None,
401 attribute_form_default: None,
402 errors: Vec::new(),
403 }
404 }
405}
406
407impl Default for XsdSchema {
408 fn default() -> Self {
409 Self::new()
410 }
411}
412
413#[derive(Debug)]
422pub struct XsdValidCtxt {
423 pub schema: Option<XsdSchema>,
425 pub errors: Vec<String>,
427 pub nb_errors: i32,
429 pub create_defaults: bool,
433}
434
435impl XsdValidCtxt {
436 pub const fn new() -> Self {
438 Self {
439 schema: None,
440 errors: Vec::new(),
441 nb_errors: 0,
442 create_defaults: false,
443 }
444 }
445}
446
447impl Default for XsdValidCtxt {
448 fn default() -> Self {
449 Self::new()
450 }
451}
452
453unsafe fn get_node_text(node: *mut _xmlNode) -> String {
463 if node.is_null() {
464 return String::new();
465 }
466 let mut result = String::new();
467 unsafe {
468 let mut child = (*node).children;
469 while !child.is_null() {
470 if ((*child).type_ == XML_TEXT_NODE as c_int
471 || (*child).type_ == XML_CDATA_SECTION_NODE as c_int)
472 && !(*child).content.is_null()
473 {
474 let content = (*child).content;
475 let mut len = 0;
476 while *content.add(len) != 0 {
477 len += 1;
478 }
479 let slice = std::slice::from_raw_parts(content, len);
480 result.push_str(&String::from_utf8_lossy(slice));
481 }
482 child = (*child).next;
483 }
484 }
485 result
486}
487
488unsafe fn get_attr(node: *mut _xmlNode, name: &str) -> Option<String> {
494 if node.is_null() {
495 return None;
496 }
497 unsafe {
498 let mut prop = (*node).properties;
499 while !prop.is_null() {
500 let prop_name = (*prop).name;
501 if !prop_name.is_null() {
502 let mut len = 0;
503 while *prop_name.add(len) != 0 {
504 len += 1;
505 }
506 let slice = std::slice::from_raw_parts(prop_name, len);
507 if let Ok(s) = std::str::from_utf8(slice) {
508 if s == name {
509 return Some(get_node_text(prop as *mut _xmlNode));
510 }
511 }
512 }
513 prop = (*prop).next;
514 }
515 }
516 None
517}
518
519unsafe fn get_attr_bool(node: *mut _xmlNode, name: &str) -> bool {
525 unsafe {
526 match get_attr(node, name) {
527 Some(v) => v == "true" || v == "1",
528 None => false,
529 }
530 }
531}
532
533#[allow(dead_code)]
539unsafe fn get_attr_int(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
540 unsafe {
541 match get_attr(node, name) {
542 Some(v) => v.parse::<i32>().unwrap_or(default),
543 None => default,
544 }
545 }
546}
547
548unsafe fn get_attr_occurs(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
554 unsafe {
555 match get_attr(node, name) {
556 Some(v) => {
557 if v == "unbounded" {
558 -1
559 } else {
560 v.parse::<i32>().unwrap_or(default)
561 }
562 }
563 None => default,
564 }
565 }
566}
567
568unsafe fn node_is(node: *mut _xmlNode, local_name: &str) -> bool {
574 if node.is_null() {
575 return false;
576 }
577 unsafe {
578 let name = (*node).name;
579 if name.is_null() {
580 return false;
581 }
582 let mut len = 0;
583 while *name.add(len) != 0 {
584 len += 1;
585 }
586 let slice = std::slice::from_raw_parts(name, len);
587 if let Ok(s) = std::str::from_utf8(slice) {
588 let local = if let Some(pos) = s.find(':') {
590 &s[pos + 1..]
591 } else {
592 s
593 };
594 return local == local_name;
595 }
596 }
597 false
598}
599
600fn parse_datatype_kind(name: &str) -> Option<XsdDatatypeKind> {
602 let local = if let Some(pos) = name.find(':') {
604 &name[pos + 1..]
605 } else {
606 name
607 };
608
609 match local {
610 "string" => Some(XsdDatatypeKind::String),
611 "boolean" => Some(XsdDatatypeKind::Boolean),
612 "decimal" => Some(XsdDatatypeKind::Decimal),
613 "float" => Some(XsdDatatypeKind::Float),
614 "double" => Some(XsdDatatypeKind::Double),
615 "duration" => Some(XsdDatatypeKind::Duration),
616 "dateTime" => Some(XsdDatatypeKind::DateTime),
617 "time" => Some(XsdDatatypeKind::Time),
618 "date" => Some(XsdDatatypeKind::Date),
619 "gYearMonth" => Some(XsdDatatypeKind::GYearMonth),
620 "gYear" => Some(XsdDatatypeKind::GYear),
621 "gMonthDay" => Some(XsdDatatypeKind::GMonthDay),
622 "gDay" => Some(XsdDatatypeKind::GDay),
623 "gMonth" => Some(XsdDatatypeKind::GMonth),
624 "hexBinary" => Some(XsdDatatypeKind::HexBinary),
625 "base64Binary" => Some(XsdDatatypeKind::Base64Binary),
626 "anyURI" => Some(XsdDatatypeKind::AnyURI),
627 "QName" => Some(XsdDatatypeKind::QName),
628 "NOTATION" => Some(XsdDatatypeKind::Notation),
629 "normalizedString" => Some(XsdDatatypeKind::NormalizedString),
630 "token" => Some(XsdDatatypeKind::Token),
631 "language" => Some(XsdDatatypeKind::Language),
632 "NMTOKEN" => Some(XsdDatatypeKind::Nmtoken),
633 "NMTOKENS" => Some(XsdDatatypeKind::Nmtokens),
634 "Name" => Some(XsdDatatypeKind::Name),
635 "NCName" => Some(XsdDatatypeKind::NCName),
636 "ID" => Some(XsdDatatypeKind::Id),
637 "IDREF" => Some(XsdDatatypeKind::Idref),
638 "IDREFS" => Some(XsdDatatypeKind::Idrefs),
639 "ENTITY" => Some(XsdDatatypeKind::Entity),
640 "ENTITIES" => Some(XsdDatatypeKind::Entities),
641 "integer" => Some(XsdDatatypeKind::Integer),
642 "nonPositiveInteger" => Some(XsdDatatypeKind::NonPositiveInteger),
643 "negativeInteger" => Some(XsdDatatypeKind::NegativeInteger),
644 "long" => Some(XsdDatatypeKind::Long),
645 "int" => Some(XsdDatatypeKind::Int),
646 "short" => Some(XsdDatatypeKind::Short),
647 "byte" => Some(XsdDatatypeKind::Byte),
648 "nonNegativeInteger" => Some(XsdDatatypeKind::NonNegativeInteger),
649 "unsignedLong" => Some(XsdDatatypeKind::UnsignedLong),
650 "unsignedInt" => Some(XsdDatatypeKind::UnsignedInt),
651 "unsignedShort" => Some(XsdDatatypeKind::UnsignedShort),
652 "unsignedByte" => Some(XsdDatatypeKind::UnsignedByte),
653 "positiveInteger" => Some(XsdDatatypeKind::PositiveInteger),
654 _ => None,
655 }
656}
657
658const fn datatype_kind_qname(kind: &XsdDatatypeKind) -> &'static str {
661 match kind {
662 XsdDatatypeKind::String => "xs:string",
663 XsdDatatypeKind::Boolean => "xs:boolean",
664 XsdDatatypeKind::Decimal => "xs:decimal",
665 XsdDatatypeKind::Float => "xs:float",
666 XsdDatatypeKind::Double => "xs:double",
667 XsdDatatypeKind::Duration => "xs:duration",
668 XsdDatatypeKind::DateTime => "xs:dateTime",
669 XsdDatatypeKind::Time => "xs:time",
670 XsdDatatypeKind::Date => "xs:date",
671 XsdDatatypeKind::GYearMonth => "xs:gYearMonth",
672 XsdDatatypeKind::GYear => "xs:gYear",
673 XsdDatatypeKind::GMonthDay => "xs:gMonthDay",
674 XsdDatatypeKind::GDay => "xs:gDay",
675 XsdDatatypeKind::GMonth => "xs:gMonth",
676 XsdDatatypeKind::HexBinary => "xs:hexBinary",
677 XsdDatatypeKind::Base64Binary => "xs:base64Binary",
678 XsdDatatypeKind::AnyURI => "xs:anyURI",
679 XsdDatatypeKind::QName => "xs:QName",
680 XsdDatatypeKind::Notation => "xs:NOTATION",
681 XsdDatatypeKind::NormalizedString => "xs:normalizedString",
682 XsdDatatypeKind::Token => "xs:token",
683 XsdDatatypeKind::Language => "xs:language",
684 XsdDatatypeKind::Nmtoken => "xs:NMTOKEN",
685 XsdDatatypeKind::Nmtokens => "xs:NMTOKENS",
686 XsdDatatypeKind::Name => "xs:Name",
687 XsdDatatypeKind::NCName => "xs:NCName",
688 XsdDatatypeKind::Id => "xs:ID",
689 XsdDatatypeKind::Idref => "xs:IDREF",
690 XsdDatatypeKind::Idrefs => "xs:IDREFS",
691 XsdDatatypeKind::Entity => "xs:ENTITY",
692 XsdDatatypeKind::Entities => "xs:ENTITIES",
693 XsdDatatypeKind::Integer => "xs:integer",
694 XsdDatatypeKind::NonPositiveInteger => "xs:nonPositiveInteger",
695 XsdDatatypeKind::NegativeInteger => "xs:negativeInteger",
696 XsdDatatypeKind::Long => "xs:long",
697 XsdDatatypeKind::Int => "xs:int",
698 XsdDatatypeKind::Short => "xs:short",
699 XsdDatatypeKind::Byte => "xs:byte",
700 XsdDatatypeKind::NonNegativeInteger => "xs:nonNegativeInteger",
701 XsdDatatypeKind::UnsignedLong => "xs:unsignedLong",
702 XsdDatatypeKind::UnsignedInt => "xs:unsignedInt",
703 XsdDatatypeKind::UnsignedShort => "xs:unsignedShort",
704 XsdDatatypeKind::UnsignedByte => "xs:unsignedByte",
705 XsdDatatypeKind::PositiveInteger => "xs:positiveInteger",
706 XsdDatatypeKind::FacetPattern => "pattern",
707 XsdDatatypeKind::FacetEnumeration => "enumeration",
708 XsdDatatypeKind::FacetMinInclusive => "minInclusive",
709 XsdDatatypeKind::FacetMaxInclusive => "maxInclusive",
710 XsdDatatypeKind::FacetMinExclusive => "minExclusive",
711 XsdDatatypeKind::FacetMaxExclusive => "maxExclusive",
712 XsdDatatypeKind::FacetMinLength => "minLength",
713 XsdDatatypeKind::FacetMaxLength => "maxLength",
714 XsdDatatypeKind::FacetLength => "length",
715 XsdDatatypeKind::FacetWhiteSpace => "whiteSpace",
716 XsdDatatypeKind::FacetFractionDigits => "fractionDigits",
717 XsdDatatypeKind::FacetTotalDigits => "totalDigits",
718 }
719}
720
721fn parse_facet_kind(name: &str) -> Option<XsdDatatypeKind> {
723 match name {
724 "pattern" => Some(XsdDatatypeKind::FacetPattern),
725 "enumeration" => Some(XsdDatatypeKind::FacetEnumeration),
726 "minInclusive" => Some(XsdDatatypeKind::FacetMinInclusive),
727 "maxInclusive" => Some(XsdDatatypeKind::FacetMaxInclusive),
728 "minExclusive" => Some(XsdDatatypeKind::FacetMinExclusive),
729 "maxExclusive" => Some(XsdDatatypeKind::FacetMaxExclusive),
730 "minLength" => Some(XsdDatatypeKind::FacetMinLength),
731 "maxLength" => Some(XsdDatatypeKind::FacetMaxLength),
732 "length" => Some(XsdDatatypeKind::FacetLength),
733 "whiteSpace" => Some(XsdDatatypeKind::FacetWhiteSpace),
734 "fractionDigits" => Some(XsdDatatypeKind::FacetFractionDigits),
735 "totalDigits" => Some(XsdDatatypeKind::FacetTotalDigits),
736 _ => None,
737 }
738}
739
740pub fn xsd_parse(xml_doc: &str) -> Result<XsdSchema, String> {
759 let doc_ptr = unsafe {
761 crate::abi::exports_xml2::xmlReadMemory(
762 xml_doc.as_ptr() as *const c_char,
763 xml_doc.len() as c_int,
764 c"schema.xsd".as_ptr() as *const c_char,
765 ptr::null(),
766 0,
767 )
768 };
769
770 if doc_ptr.is_null() {
771 return Err("Failed to parse schema XML document".to_string());
772 }
773
774 let result = unsafe { xsd_parse_schema_doc(doc_ptr) };
775 unsafe {
776 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
777 }
778 result
779}
780
781unsafe fn xsd_parse_schema_doc(doc: *mut _xmlDoc) -> Result<XsdSchema, String> {
787 unsafe {
788 let root = (*doc).children;
789 if root.is_null() {
790 return Err("Schema document has no root element".to_string());
791 }
792
793 let mut schema_node = root;
795 while !schema_node.is_null()
796 && ((*schema_node).type_ != XML_ELEMENT_NODE as c_int
797 || !node_is(schema_node, "schema"))
798 {
799 schema_node = (*schema_node).next;
800 }
801
802 if schema_node.is_null() {
803 return Err("Schema document root is not <schema>".to_string());
804 }
805
806 Ok(xsd_parse_schema_node(schema_node))
807 }
808}
809
810unsafe fn xsd_parse_schema_node(node: *mut _xmlNode) -> XsdSchema {
816 unsafe {
817 let mut schema = XsdSchema::new();
818 schema.target_namespace = get_attr(node, "targetNamespace");
819 schema.element_form_default = get_attr(node, "elementFormDefault");
820 schema.attribute_form_default = get_attr(node, "attributeFormDefault");
821
822 let mut child = (*node).children;
824 while !child.is_null() {
825 if (*child).type_ == XML_ELEMENT_NODE as c_int {
826 let comp = xsd_parse_component(child, &schema);
827 if comp.component_type != XsdComponentType::Annotation {
828 schema.components.push(comp);
829 }
830 }
831 child = (*child).next;
832 }
833
834 if schema.target_namespace.is_some() {
843 for comp in &mut schema.components {
844 if comp.target_namespace.is_none() {
845 comp.target_namespace = schema.target_namespace.clone();
846 }
847 }
848 }
849
850 schema
851 }
852}
853
854unsafe fn xsd_parse_component(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
860 unsafe {
861 let name_str = if !(*node).name.is_null() {
863 let mut len = 0;
864 while *(*node).name.add(len) != 0 {
865 len += 1;
866 }
867 let slice = std::slice::from_raw_parts((*node).name, len);
868 if let Ok(s) = std::str::from_utf8(slice) {
869 if let Some(pos) = s.find(':') {
870 s[pos + 1..].to_string()
871 } else {
872 s.to_string()
873 }
874 } else {
875 String::new()
876 }
877 } else {
878 String::new()
879 };
880
881 match name_str.as_str() {
882 "element" => xsd_parse_element(node, schema),
883 "attribute" => xsd_parse_attribute_node(node, schema),
884 "complexType" => xsd_parse_complex_type(node, schema),
885 "simpleType" => xsd_parse_simple_type(node, schema),
886 "sequence" => xsd_parse_model_group(node, XsdComponentType::Sequence, schema),
887 "choice" => xsd_parse_model_group(node, XsdComponentType::Choice, schema),
888 "all" => xsd_parse_model_group(node, XsdComponentType::All, schema),
889 "restriction" => xsd_parse_restriction(node, schema),
890 "extension" => xsd_parse_extension(node, schema),
891 "list" => xsd_parse_list(node, schema),
892 "union" => xsd_parse_union(node, schema),
893 "annotation" => xsd_parse_annotation(node),
894 "any" => xsd_parse_any(node, schema),
895 "anyAttribute" => XsdComponent::new(XsdComponentType::AnyAttribute),
896 "group" => xsd_parse_group(node, schema),
897 "attributeGroup" => xsd_parse_attribute_group(node, schema),
898 "unique" => xsd_parse_identity_constraint(node, XsdComponentType::Unique, schema),
899 "key" => xsd_parse_identity_constraint(node, XsdComponentType::Key, schema),
900 "keyref" => xsd_parse_identity_constraint(node, XsdComponentType::KeyRef, schema),
901 "pattern" | "enumeration" | "minInclusive" | "maxInclusive" | "minExclusive"
903 | "maxExclusive" | "minLength" | "maxLength" | "length" | "whiteSpace"
904 | "fractionDigits" | "totalDigits" => xsd_parse_facet(node),
905 "simpleContent" => xsd_parse_simple_content(node, schema),
907 "complexContent" => xsd_parse_complex_content(node, schema),
908 _ => {
909 let mut comp = XsdComponent::new(XsdComponentType::Schema);
911 if let Ok(s) = std::str::from_utf8(std::slice::from_raw_parts((*node).name, {
912 let mut len = 0;
913 while *(*node).name.add(len) != 0 {
914 len += 1;
915 }
916 len
917 })) {
918 comp.name = Some(s.to_string());
919 }
920 comp
921 }
922 }
923 }
924}
925
926unsafe fn xsd_parse_element(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
932 unsafe {
933 let mut comp = XsdComponent::new(XsdComponentType::Element);
934 comp.name = get_attr(node, "name");
935 comp.ref_name = get_attr(node, "ref");
936 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
937 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
938 comp.is_abstract = get_attr_bool(node, "abstract");
939 comp.is_final = get_attr_bool(node, "final");
940 comp.substitution_group = get_attr(node, "substitutionGroup");
941 comp.form = get_attr(node, "form");
942
943 if let Some(type_name) = get_attr(node, "type") {
945 comp.datatype = parse_datatype_kind(&type_name);
946 if comp.datatype.is_none() {
948 comp.base = Some(type_name);
949 }
950 }
951
952 comp.default_value = get_attr(node, "default");
954 comp.fixed_value = get_attr(node, "fixed");
955
956 let mut child = (*node).children;
958 while !child.is_null() {
959 if (*child).type_ == XML_ELEMENT_NODE as c_int {
960 let child_comp = xsd_parse_component(child, schema);
961 match child_comp.component_type {
962 XsdComponentType::ComplexType | XsdComponentType::SimpleType => {
963 if let Some(ref name) = child_comp.name {
965 comp.base = Some(name.clone());
966 }
967 comp.children.push(child_comp);
968 }
969 XsdComponentType::Annotation => {
970 }
972 _ => {
973 comp.children.push(child_comp);
974 }
975 }
976 }
977 child = (*child).next;
978 }
979
980 comp
981 }
982}
983
984unsafe fn xsd_parse_attribute_node(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
990 unsafe {
991 let mut comp = XsdComponent::new(XsdComponentType::Attribute);
992 comp.name = get_attr(node, "name");
993 comp.ref_name = get_attr(node, "ref");
994 comp.form = get_attr(node, "form");
995
996 if let Some(type_name) = get_attr(node, "type") {
998 comp.datatype = parse_datatype_kind(&type_name);
999 if comp.datatype.is_none() {
1000 comp.base = Some(type_name);
1001 }
1002 }
1003
1004 let use_attr = get_attr(node, "use");
1006 if let Some(ref use_val) = use_attr {
1007 if use_val == "required" {
1008 comp.min_occurs = 1;
1009 } else if use_val == "prohibited" {
1010 comp.min_occurs = 0;
1011 comp.max_occurs = 0;
1012 } else {
1013 comp.min_occurs = 0;
1015 }
1016 } else {
1017 comp.min_occurs = 0; }
1019
1020 comp.default_value = get_attr(node, "default");
1021 comp.fixed_value = get_attr(node, "fixed");
1022
1023 let mut child = (*node).children;
1025 while !child.is_null() {
1026 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1027 let child_comp = xsd_parse_component(child, schema);
1028 if child_comp.component_type == XsdComponentType::SimpleType {
1029 if let Some(ref name) = child_comp.name {
1030 comp.base = Some(name.clone());
1031 }
1032 comp.children.push(child_comp);
1033 }
1034 }
1035 child = (*child).next;
1036 }
1037
1038 comp
1039 }
1040}
1041
1042unsafe fn xsd_parse_complex_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1048 unsafe {
1049 let mut comp = XsdComponent::new(XsdComponentType::ComplexType);
1050 comp.name = get_attr(node, "name");
1051 comp.mixed = get_attr_bool(node, "mixed");
1052 comp.is_abstract = get_attr_bool(node, "abstract");
1053 comp.is_final = get_attr_bool(node, "final");
1054
1055 let mut child = (*node).children;
1057 while !child.is_null() {
1058 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1059 let child_comp = xsd_parse_component(child, schema);
1060 match child_comp.component_type {
1061 XsdComponentType::SimpleContent
1062 | XsdComponentType::ComplexContent
1063 | XsdComponentType::Sequence
1064 | XsdComponentType::Choice
1065 | XsdComponentType::All
1066 | XsdComponentType::Group
1067 | XsdComponentType::Any
1068 | XsdComponentType::Annotation => {
1069 if child_comp.component_type == XsdComponentType::SimpleContent {
1070 comp.children.extend(child_comp.children);
1072 } else if child_comp.component_type == XsdComponentType::ComplexContent {
1073 comp.children.extend(child_comp.children);
1075 } else {
1076 comp.children.push(child_comp);
1077 }
1078 }
1079 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1080 comp.attributes.push(child_comp);
1081 }
1082 _ => {
1083 comp.children.push(child_comp);
1084 }
1085 }
1086 }
1087 child = (*child).next;
1088 }
1089
1090 comp
1091 }
1092}
1093
1094unsafe fn xsd_parse_simple_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1100 unsafe {
1101 let mut comp = XsdComponent::new(XsdComponentType::SimpleType);
1102 comp.name = get_attr(node, "name");
1103
1104 let mut child = (*node).children;
1106 while !child.is_null() {
1107 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1108 let child_comp = xsd_parse_component(child, schema);
1109 match child_comp.component_type {
1110 XsdComponentType::Restriction
1111 | XsdComponentType::List
1112 | XsdComponentType::Union => {
1113 comp.datatype = child_comp.datatype;
1114 comp.base = child_comp.base;
1115 comp.facets = child_comp.facets;
1116 comp.children.extend(child_comp.children);
1117 }
1118 _ => {}
1119 }
1120 }
1121 child = (*child).next;
1122 }
1123
1124 comp
1125 }
1126}
1127
1128unsafe fn xsd_parse_model_group(
1134 node: *mut _xmlNode,
1135 ctype: XsdComponentType,
1136 schema: &XsdSchema,
1137) -> XsdComponent {
1138 unsafe {
1139 let mut comp = XsdComponent::new(ctype);
1140 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1141 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1142
1143 let mut child = (*node).children;
1144 while !child.is_null() {
1145 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1146 let child_comp = xsd_parse_component(child, schema);
1147 match child_comp.component_type {
1148 XsdComponentType::Annotation => {}
1149 _ => {
1150 comp.children.push(child_comp);
1151 }
1152 }
1153 }
1154 child = (*child).next;
1155 }
1156
1157 comp
1158 }
1159}
1160
1161unsafe fn xsd_parse_restriction(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1167 unsafe {
1168 let mut comp = XsdComponent::new(XsdComponentType::Restriction);
1169 comp.base = get_attr(node, "base");
1170
1171 if let Some(ref base_name) = comp.base {
1173 comp.datatype = parse_datatype_kind(base_name);
1174 }
1175
1176 let mut child = (*node).children;
1178 while !child.is_null() {
1179 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1180 let child_comp = xsd_parse_component(child, schema);
1181 match child_comp.component_type {
1182 XsdComponentType::Sequence
1183 | XsdComponentType::Choice
1184 | XsdComponentType::All
1185 | XsdComponentType::Group
1186 | XsdComponentType::Any
1187 | XsdComponentType::Annotation => {
1188 comp.children.push(child_comp);
1189 }
1190 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1191 comp.attributes.push(child_comp);
1192 }
1193 XsdComponentType::SimpleType => {
1194 comp.children.push(child_comp);
1196 }
1197 _ => {
1198 if let Some(facet_kind) =
1200 parse_facet_kind(&format!("{:?}", child_comp.component_type))
1201 {
1202 if let Some(val) = get_attr(child, "value") {
1204 comp.facets.push((facet_kind, val));
1205 }
1206 }
1207 let name_str = if !(*child).name.is_null() {
1209 let mut len = 0;
1210 while *(*child).name.add(len) != 0 {
1211 len += 1;
1212 }
1213 let slice = std::slice::from_raw_parts((*child).name, len);
1214 std::str::from_utf8(slice)
1215 .ok()
1216 .map(|s| {
1217 if let Some(pos) = s.find(':') {
1218 s[pos + 1..].to_string()
1219 } else {
1220 s.to_string()
1221 }
1222 })
1223 .unwrap_or_default()
1224 } else {
1225 String::new()
1226 };
1227 if !name_str.is_empty() {
1228 if let Some(facet_kind) = parse_facet_kind(&name_str) {
1229 if let Some(val) = get_attr(child, "value") {
1230 comp.facets.push((facet_kind, val));
1231 }
1232 }
1233 }
1234 }
1235 }
1236 }
1237 child = (*child).next;
1238 }
1239
1240 comp
1241 }
1242}
1243
1244unsafe fn xsd_parse_extension(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1250 unsafe {
1251 let mut comp = XsdComponent::new(XsdComponentType::Extension);
1252 comp.base = get_attr(node, "base");
1253
1254 if let Some(ref base_name) = comp.base {
1255 comp.datatype = parse_datatype_kind(base_name);
1256 }
1257
1258 let mut child = (*node).children;
1260 while !child.is_null() {
1261 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1262 let child_comp = xsd_parse_component(child, schema);
1263 match child_comp.component_type {
1264 XsdComponentType::Sequence
1265 | XsdComponentType::Choice
1266 | XsdComponentType::All
1267 | XsdComponentType::Group
1268 | XsdComponentType::Any
1269 | XsdComponentType::Annotation => {
1270 comp.children.push(child_comp);
1271 }
1272 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1273 comp.attributes.push(child_comp);
1274 }
1275 _ => {}
1276 }
1277 }
1278 child = (*child).next;
1279 }
1280
1281 comp
1282 }
1283}
1284
1285unsafe fn xsd_parse_list(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1291 unsafe {
1292 let mut comp = XsdComponent::new(XsdComponentType::List);
1293
1294 if let Some(item_type) = get_attr(node, "itemType") {
1295 comp.base = Some(item_type.clone());
1296 comp.datatype = parse_datatype_kind(&item_type);
1297 }
1298
1299 let mut child = (*node).children;
1301 while !child.is_null() {
1302 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1303 let child_comp = xsd_parse_component(child, schema);
1304 if child_comp.component_type == XsdComponentType::SimpleType {
1305 comp.datatype = child_comp.datatype;
1306 comp.base = child_comp.base;
1307 comp.facets = child_comp.facets;
1308 }
1309 }
1310 child = (*child).next;
1311 }
1312
1313 comp
1314 }
1315}
1316
1317unsafe fn xsd_parse_union(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1323 unsafe {
1324 let mut comp = XsdComponent::new(XsdComponentType::Union);
1325
1326 if let Some(member_types) = get_attr(node, "memberTypes") {
1327 comp.base = Some(member_types);
1328 }
1329
1330 let mut child = (*node).children;
1331 while !child.is_null() {
1332 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1333 let child_comp = xsd_parse_component(child, schema);
1334 if child_comp.component_type == XsdComponentType::SimpleType {
1335 comp.children.push(child_comp);
1336 }
1337 }
1338 child = (*child).next;
1339 }
1340
1341 comp
1342 }
1343}
1344
1345unsafe fn xsd_parse_annotation(node: *mut _xmlNode) -> XsdComponent {
1351 unsafe {
1352 let mut comp = XsdComponent::new(XsdComponentType::Annotation);
1353
1354 let mut child = (*node).children;
1355 while !child.is_null() {
1356 if (*child).type_ == XML_ELEMENT_NODE as c_int
1357 && (node_is(child, "documentation") || node_is(child, "appinfo"))
1358 {
1359 let text = get_node_text(child);
1360 if !text.is_empty() {
1361 comp.facets.push((XsdDatatypeKind::String, text));
1362 }
1363 }
1364 child = (*child).next;
1365 }
1366
1367 comp
1368 }
1369}
1370
1371unsafe fn xsd_parse_any(node: *mut _xmlNode, _schema: &XsdSchema) -> XsdComponent {
1377 unsafe {
1378 let mut comp = XsdComponent::new(XsdComponentType::Any);
1379 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1380 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1381
1382 let namespace_attr = get_attr(node, "namespace");
1383 if let Some(ref ns) = namespace_attr {
1384 if ns != "##any" {
1385 comp.target_namespace = Some(ns.clone());
1386 }
1387 }
1388
1389 comp
1390 }
1391}
1392
1393unsafe fn xsd_parse_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1399 unsafe {
1400 let mut comp = XsdComponent::new(XsdComponentType::Group);
1401 comp.name = get_attr(node, "name");
1402 comp.ref_name = get_attr(node, "ref");
1403 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1404 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1405
1406 let mut child = (*node).children;
1407 while !child.is_null() {
1408 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1409 let child_comp = xsd_parse_component(child, schema);
1410 match child_comp.component_type {
1411 XsdComponentType::Annotation => {}
1412 _ => {
1413 comp.children.push(child_comp);
1414 }
1415 }
1416 }
1417 child = (*child).next;
1418 }
1419
1420 comp
1421 }
1422}
1423
1424unsafe fn xsd_parse_attribute_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1430 unsafe {
1431 let mut comp = XsdComponent::new(XsdComponentType::AttributeGroup);
1432 comp.name = get_attr(node, "name");
1433 comp.ref_name = get_attr(node, "ref");
1434
1435 let mut child = (*node).children;
1436 while !child.is_null() {
1437 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1438 let child_comp = xsd_parse_component(child, schema);
1439 match child_comp.component_type {
1440 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1441 comp.attributes.push(child_comp);
1442 }
1443 _ => {}
1444 }
1445 }
1446 child = (*child).next;
1447 }
1448
1449 comp
1450 }
1451}
1452
1453unsafe fn xsd_parse_facet(node: *mut _xmlNode) -> XsdComponent {
1459 unsafe {
1460 let name_str = if !(*node).name.is_null() {
1461 let mut len = 0;
1462 while *(*node).name.add(len) != 0 {
1463 len += 1;
1464 }
1465 let slice = std::slice::from_raw_parts((*node).name, len);
1466 std::str::from_utf8(slice)
1467 .ok()
1468 .map(|s| {
1469 if let Some(pos) = s.find(':') {
1470 s[pos + 1..].to_string()
1471 } else {
1472 s.to_string()
1473 }
1474 })
1475 .unwrap_or_default()
1476 } else {
1477 String::new()
1478 };
1479
1480 let facet_kind = parse_facet_kind(&name_str).unwrap_or(XsdDatatypeKind::String);
1481 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1482 let val = get_attr(node, "value").unwrap_or_default();
1483 comp.facets.push((facet_kind, val));
1484 comp.datatype = Some(facet_kind);
1485
1486 comp
1487 }
1488}
1489
1490unsafe fn xsd_parse_simple_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1496 unsafe {
1497 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1498
1499 let mut child = (*node).children;
1500 while !child.is_null() {
1501 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1502 let child_comp = xsd_parse_component(child, schema);
1503 match child_comp.component_type {
1504 XsdComponentType::Restriction | XsdComponentType::Extension => {
1505 comp.children.push(child_comp);
1506 }
1507 _ => {}
1508 }
1509 }
1510 child = (*child).next;
1511 }
1512
1513 comp
1514 }
1515}
1516
1517unsafe fn xsd_parse_complex_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1523 unsafe {
1524 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1525
1526 let mut child = (*node).children;
1527 while !child.is_null() {
1528 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1529 let child_comp = xsd_parse_component(child, schema);
1530 match child_comp.component_type {
1531 XsdComponentType::Restriction | XsdComponentType::Extension => {
1532 comp.children.push(child_comp);
1533 }
1534 _ => {}
1535 }
1536 }
1537 child = (*child).next;
1538 }
1539
1540 comp
1541 }
1542}
1543
1544unsafe fn xsd_parse_identity_constraint(
1550 node: *mut _xmlNode,
1551 ctype: XsdComponentType,
1552 schema: &XsdSchema,
1553) -> XsdComponent {
1554 unsafe {
1555 let mut comp = XsdComponent::new(ctype);
1556 comp.name = get_attr(node, "name");
1557
1558 if ctype == XsdComponentType::KeyRef {
1559 comp.ref_name = get_attr(node, "refer");
1560 }
1561
1562 let mut child = (*node).children;
1563 while !child.is_null() {
1564 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1565 let child_comp = xsd_parse_component(child, schema);
1566 match child_comp.component_type {
1567 XsdComponentType::Selector | XsdComponentType::Field => {
1568 comp.children.push(child_comp);
1569 }
1570 _ => {}
1571 }
1572 }
1573 child = (*child).next;
1574 }
1575
1576 comp
1577 }
1578}
1579
1580pub fn xsd_validate_datatype(
1590 kind: &XsdDatatypeKind,
1591 value: &str,
1592 facets: &[(XsdDatatypeKind, String)],
1593) -> bool {
1594 if !validate_base_type(kind, value) {
1596 return false;
1597 }
1598
1599 let mut has_enumeration = false;
1604 let mut enumeration_match = false;
1605
1606 for (facet_kind, facet_value) in facets {
1607 if *facet_kind == XsdDatatypeKind::FacetEnumeration {
1608 has_enumeration = true;
1609 if xsd_validate_facet(kind, value, facet_kind, facet_value) {
1610 enumeration_match = true;
1611 }
1612 } else if !xsd_validate_facet(kind, value, facet_kind, facet_value) {
1613 return false;
1614 }
1615 }
1616
1617 if has_enumeration && !enumeration_match {
1619 return false;
1620 }
1621
1622 true
1623}
1624
1625pub fn xsd_validate_facet(
1627 _kind: &XsdDatatypeKind,
1628 value: &str,
1629 facet_kind: &XsdDatatypeKind,
1630 facet_value: &str,
1631) -> bool {
1632 match facet_kind {
1633 XsdDatatypeKind::FacetPattern => {
1634 match facet_value {
1637 r"\d+" => value.chars().all(|c| c.is_ascii_digit()),
1638 r"\d*" => value.is_empty() || value.chars().all(|c| c.is_ascii_digit()),
1639 r"[a-zA-Z]+" => value.chars().all(|c| c.is_ascii_alphabetic()),
1640 r"[a-zA-Z]*" => value.is_empty() || value.chars().all(|c| c.is_ascii_alphabetic()),
1641 r"[a-zA-Z0-9]+" => value.chars().all(|c| c.is_ascii_alphanumeric()),
1642 r"[a-zA-Z0-9_\-]+" => value
1643 .chars()
1644 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
1645 r"[a-zA-Z_][a-zA-Z0-9_\-\.]*" => {
1646 if value.is_empty() {
1647 return false;
1648 }
1649 let first = value.chars().next().unwrap();
1650 if !first.is_ascii_alphabetic() && first != '_' {
1651 return false;
1652 }
1653 value
1654 .chars()
1655 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1656 }
1657 r"[a-zA-Z_][\w\-\.]*" => {
1658 if value.is_empty() {
1659 return false;
1660 }
1661 let first = value.chars().next().unwrap();
1662 if !first.is_ascii_alphabetic() && first != '_' {
1663 return false;
1664 }
1665 value
1666 .chars()
1667 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1668 }
1669 r"\i\c*" => {
1670 if value.is_empty() {
1672 return false;
1673 }
1674 let first = value.chars().next().unwrap();
1675 if !is_name_start_char(first) {
1676 return false;
1677 }
1678 value.chars().skip(1).all(is_name_char)
1679 }
1680 r"\c+" => {
1681 if value.is_empty() {
1682 return false;
1683 }
1684 value.chars().all(is_name_char)
1685 }
1686 _ => {
1688 if facet_value.starts_with('^') && facet_value.ends_with('$') {
1689 let inner = &facet_value[1..facet_value.len() - 1];
1690 simple_glob_match(inner, value)
1691 } else {
1692 true
1694 }
1695 }
1696 }
1697 }
1698 XsdDatatypeKind::FacetEnumeration => {
1699 value == facet_value
1701 }
1702 XsdDatatypeKind::FacetMinInclusive => {
1703 compare_strings(value, facet_value) != std::cmp::Ordering::Less
1704 }
1705 XsdDatatypeKind::FacetMaxInclusive => {
1706 compare_strings(value, facet_value) != std::cmp::Ordering::Greater
1707 }
1708 XsdDatatypeKind::FacetMinExclusive => {
1709 compare_strings(value, facet_value) == std::cmp::Ordering::Greater
1710 }
1711 XsdDatatypeKind::FacetMaxExclusive => {
1712 compare_strings(value, facet_value) == std::cmp::Ordering::Less
1713 }
1714 XsdDatatypeKind::FacetMinLength => {
1715 let min = facet_value.parse::<usize>().unwrap_or(0);
1716 value.chars().count() >= min
1717 }
1718 XsdDatatypeKind::FacetMaxLength => {
1719 let max = facet_value.parse::<usize>().unwrap_or(usize::MAX);
1720 value.chars().count() <= max
1721 }
1722 XsdDatatypeKind::FacetLength => {
1723 let len = facet_value.parse::<usize>().unwrap_or(0);
1724 value.chars().count() == len
1725 }
1726 XsdDatatypeKind::FacetWhiteSpace => {
1727 match facet_value {
1729 "replace" => {
1730 true
1733 }
1734 "collapse" => {
1735 true
1737 }
1738 _ => true,
1739 }
1740 }
1741 XsdDatatypeKind::FacetFractionDigits | XsdDatatypeKind::FacetTotalDigits => {
1742 value.parse::<f64>().is_ok()
1744 }
1745 _ => true,
1746 }
1747}
1748
1749fn simple_glob_match(pattern: &str, value: &str) -> bool {
1751 let pattern_chars: Vec<char> = pattern.chars().collect();
1752 let value_chars: Vec<char> = value.chars().collect();
1753
1754 let mut pi = 0;
1755 let mut vi = 0;
1756 let mut backtrack_p = None;
1757 let mut backtrack_v = 0;
1758
1759 while vi < value_chars.len() {
1760 if pi < pattern_chars.len()
1761 && (pattern_chars[pi] == value_chars[vi] || pattern_chars[pi] == '.')
1762 {
1763 pi += 1;
1764 vi += 1;
1765 } else if pi < pattern_chars.len() && pattern_chars[pi] == '*' {
1766 backtrack_p = Some(pi);
1767 backtrack_v = vi + 1;
1768 pi += 1;
1769 } else if pi < pattern_chars.len() && pattern_chars[pi] == '+' {
1770 if pi + 1 < pattern_chars.len() && pattern_chars[pi + 1] == value_chars[vi] {
1772 pi += 1;
1773 vi += 1;
1774 while vi < value_chars.len() && value_chars[vi] == pattern_chars[pi] {
1776 vi += 1;
1777 }
1778 pi += 1;
1779 } else {
1780 return false;
1781 }
1782 } else if let Some(bp) = backtrack_p {
1783 pi = bp + 1;
1784 vi = backtrack_v;
1785 backtrack_v += 1;
1786 } else {
1787 return false;
1788 }
1789 }
1790
1791 while pi < pattern_chars.len() && (pattern_chars[pi] == '*' || pattern_chars[pi] == '+') {
1793 if pattern_chars[pi] == '+' && vi == value_chars.len() {
1794 return false; }
1796 pi += 1;
1797 }
1798
1799 pi == pattern_chars.len()
1800}
1801
1802const fn is_name_start_char(c: char) -> bool {
1804 c.is_ascii_alphabetic()
1805 || c == '_'
1806 || c == ':'
1807 || (c >= '\u{00C0}' && c <= '\u{00D6}')
1808 || (c >= '\u{00D8}' && c <= '\u{00F6}')
1809 || (c >= '\u{00F8}' && c <= '\u{02FF}')
1810 || (c >= '\u{0370}' && c <= '\u{037D}')
1811 || (c >= '\u{037F}' && c <= '\u{1FFF}')
1812 || (c >= '\u{200C}' && c <= '\u{200D}')
1813 || (c >= '\u{2070}' && c <= '\u{218F}')
1814 || (c >= '\u{2C00}' && c <= '\u{2FEF}')
1815 || (c >= '\u{3001}' && c <= '\u{D7FF}')
1816 || (c >= '\u{F900}' && c <= '\u{FDCF}')
1817 || (c >= '\u{FDF0}' && c <= '\u{FFFD}')
1818}
1819
1820const fn is_name_char(c: char) -> bool {
1822 is_name_start_char(c)
1823 || c.is_ascii_digit()
1824 || c == '-'
1825 || c == '.'
1826 || c == '\u{00B7}'
1827 || (c >= '\u{0300}' && c <= '\u{036F}')
1828 || (c >= '\u{203F}' && c <= '\u{2040}')
1829}
1830
1831fn compare_strings(a: &str, b: &str) -> std::cmp::Ordering {
1833 if let (Ok(na), Ok(nb)) = (a.parse::<f64>(), b.parse::<f64>()) {
1835 return na.partial_cmp(&nb).unwrap_or(std::cmp::Ordering::Equal);
1836 }
1837 if let (Ok(na), Ok(nb)) = (a.parse::<i64>(), b.parse::<i64>()) {
1839 return na.cmp(&nb);
1840 }
1841 a.cmp(b)
1843}
1844
1845fn validate_base_type(kind: &XsdDatatypeKind, value: &str) -> bool {
1847 match kind {
1848 XsdDatatypeKind::String => true,
1849 XsdDatatypeKind::NormalizedString => {
1850 !value.contains('\t') && !value.contains('\n') && !value.contains('\r')
1852 }
1853 XsdDatatypeKind::Token => {
1854 if value.is_empty() {
1856 return true;
1857 }
1858 if value.starts_with(' ') || value.ends_with(' ') {
1859 return false;
1860 }
1861 !value.contains(" ")
1862 && !value.contains('\t')
1863 && !value.contains('\n')
1864 && !value.contains('\r')
1865 }
1866 XsdDatatypeKind::Language => {
1867 if value.is_empty() {
1870 return false;
1871 }
1872 let segments: Vec<&str> = value.split('-').collect();
1873 if segments.is_empty() {
1874 return false;
1875 }
1876 if segments[0].is_empty() || !segments[0].chars().all(|c| c.is_ascii_alphabetic()) {
1878 return false;
1879 }
1880 if segments[0].len() > 8 {
1881 return false;
1882 }
1883 for seg in &segments[1..] {
1885 if seg.is_empty() || seg.len() > 8 {
1886 return false;
1887 }
1888 if !seg.chars().all(|c| c.is_ascii_alphanumeric()) {
1889 return false;
1890 }
1891 }
1892 true
1893 }
1894 XsdDatatypeKind::Name => {
1895 if value.is_empty() {
1896 return false;
1897 }
1898 let mut chars = value.chars();
1899 let first = chars.next().unwrap();
1900 if !is_name_start_char(first) {
1901 return false;
1902 }
1903 chars.all(is_name_char)
1904 }
1905 XsdDatatypeKind::NCName
1906 | XsdDatatypeKind::Id
1907 | XsdDatatypeKind::Idref
1908 | XsdDatatypeKind::Entity => {
1909 if value.is_empty() || value.contains(':') {
1911 return false;
1912 }
1913 let mut chars = value.chars();
1914 let first = chars.next().unwrap();
1915 if !is_name_start_char(first) {
1916 return false;
1917 }
1918 chars.all(is_name_char)
1919 }
1920 XsdDatatypeKind::Boolean => {
1921 matches!(value, "true" | "false" | "1" | "0")
1922 }
1923 XsdDatatypeKind::Decimal
1924 | XsdDatatypeKind::Integer
1925 | XsdDatatypeKind::NonPositiveInteger
1926 | XsdDatatypeKind::NegativeInteger
1927 | XsdDatatypeKind::Long
1928 | XsdDatatypeKind::Int
1929 | XsdDatatypeKind::Short
1930 | XsdDatatypeKind::Byte
1931 | XsdDatatypeKind::NonNegativeInteger
1932 | XsdDatatypeKind::UnsignedLong
1933 | XsdDatatypeKind::UnsignedInt
1934 | XsdDatatypeKind::UnsignedShort
1935 | XsdDatatypeKind::UnsignedByte
1936 | XsdDatatypeKind::PositiveInteger => {
1937 if value.is_empty() {
1939 return false;
1940 }
1941 let mut chars = value.chars().peekable();
1942 if *chars.peek().unwrap_or(&'\0') == '-' || *chars.peek().unwrap_or(&'\0') == '+' {
1943 chars.next();
1944 }
1945 let mut has_dot = false;
1946 let mut has_digit = false;
1947 for c in chars {
1948 if c == '.' {
1949 if has_dot {
1950 return false;
1951 }
1952 has_dot = true;
1953 } else if c.is_ascii_digit() {
1954 has_digit = true;
1955 } else {
1956 return false;
1957 }
1958 }
1959 if !has_digit {
1960 return false;
1961 }
1962
1963 if has_dot && *kind != XsdDatatypeKind::Decimal {
1966 return false;
1967 }
1968
1969 match kind {
1970 XsdDatatypeKind::NonPositiveInteger => {
1971 if let Ok(v) = value.parse::<i64>() {
1972 v <= 0
1973 } else {
1974 false
1975 }
1976 }
1977 XsdDatatypeKind::NegativeInteger => {
1978 if let Ok(v) = value.parse::<i64>() {
1979 v < 0
1980 } else {
1981 false
1982 }
1983 }
1984 XsdDatatypeKind::NonNegativeInteger => {
1985 if let Ok(v) = value.parse::<i64>() {
1986 v >= 0
1987 } else {
1988 false
1989 }
1990 }
1991 XsdDatatypeKind::PositiveInteger => {
1992 if let Ok(v) = value.parse::<i64>() {
1993 v > 0
1994 } else {
1995 false
1996 }
1997 }
1998 XsdDatatypeKind::UnsignedLong
1999 | XsdDatatypeKind::UnsignedInt
2000 | XsdDatatypeKind::UnsignedShort
2001 | XsdDatatypeKind::UnsignedByte => {
2002 if let Ok(v) = value.parse::<u64>() {
2003 match kind {
2004 XsdDatatypeKind::UnsignedInt => v <= u64::from(u32::MAX),
2005 XsdDatatypeKind::UnsignedShort => v <= u64::from(u16::MAX),
2006 XsdDatatypeKind::UnsignedByte => v <= u64::from(u8::MAX),
2007 _ => true,
2008 }
2009 } else {
2010 false
2011 }
2012 }
2013 XsdDatatypeKind::Long => value.parse::<i64>().is_ok(),
2014 XsdDatatypeKind::Int => value.parse::<i32>().is_ok(),
2015 XsdDatatypeKind::Short => value.parse::<i16>().is_ok(),
2016 XsdDatatypeKind::Byte => value.parse::<i8>().is_ok(),
2017 _ => true,
2018 }
2019 }
2020 XsdDatatypeKind::Float | XsdDatatypeKind::Double => {
2021 matches!(value, "INF" | "-INF" | "NaN") || value.parse::<f64>().is_ok()
2023 }
2024 XsdDatatypeKind::Duration => {
2025 if !value.starts_with('-') && !value.starts_with('P') {
2027 return false;
2028 }
2029 let dur = value.strip_prefix('-').unwrap_or(value);
2030 if !dur.starts_with('P') {
2031 return false;
2032 }
2033 let rest = &dur[1..];
2034 if rest.is_empty() {
2035 return false;
2036 }
2037 let has_t = rest.contains('T');
2038 let _date_part = if has_t {
2039 &rest[..rest.find('T').unwrap()]
2040 } else {
2041 rest
2042 };
2043 if has_t {
2044 let time_part = &rest[rest.find('T').unwrap() + 1..];
2045 if time_part.is_empty() {
2046 return false;
2047 }
2048 }
2049 true
2050 }
2051 XsdDatatypeKind::DateTime => {
2052 if value.len() < 19 {
2054 return false;
2055 }
2056 let chars: Vec<char> = value.chars().collect();
2057 chars[4] == '-'
2058 && chars[7] == '-'
2059 && chars[10] == 'T'
2060 && chars[13] == ':'
2061 && chars[16] == ':'
2062 }
2063 XsdDatatypeKind::Date => {
2064 if value.len() < 10 {
2066 return false;
2067 }
2068 let chars: Vec<char> = value.chars().collect();
2069 chars[4] == '-' && chars[7] == '-'
2070 }
2071 XsdDatatypeKind::Time => {
2072 if value.len() < 8 {
2074 return false;
2075 }
2076 let chars: Vec<char> = value.chars().collect();
2077 chars[2] == ':' && chars[5] == ':'
2078 }
2079 XsdDatatypeKind::GYear => {
2080 if value.len() < 4 {
2082 return false;
2083 }
2084 value.chars().take(4).all(|c| c.is_ascii_digit())
2085 }
2086 XsdDatatypeKind::GYearMonth => {
2087 if value.len() < 7 {
2089 return false;
2090 }
2091 let chars: Vec<char> = value.chars().collect();
2092 chars[4] == '-'
2093 }
2094 XsdDatatypeKind::GMonthDay => {
2095 if value.len() < 6 || !value.starts_with("--") {
2097 return false;
2098 }
2099 let chars: Vec<char> = value.chars().collect();
2100 chars[4] == '-'
2101 }
2102 XsdDatatypeKind::GDay => {
2103 value.starts_with("---") && value.len() >= 4
2105 }
2106 XsdDatatypeKind::GMonth => {
2107 value.starts_with("--") && value.len() >= 3
2109 }
2110 XsdDatatypeKind::HexBinary => {
2111 if !value.len().is_multiple_of(2) {
2112 return false;
2113 }
2114 value.chars().all(|c| c.is_ascii_hexdigit())
2115 }
2116 XsdDatatypeKind::Base64Binary => {
2117 if value.is_empty() {
2119 return true;
2120 }
2121 let valid_chars =
2122 |c: char| c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=';
2123 value.chars().all(valid_chars)
2124 }
2125 XsdDatatypeKind::AnyURI => {
2126 !value.is_empty()
2128 }
2129 XsdDatatypeKind::QName => {
2130 if let Some(pos) = value.find(':') {
2132 let prefix = &value[..pos];
2133 let local = &value[pos + 1..];
2134 is_ncname(prefix) && is_ncname(local)
2135 } else {
2136 is_ncname(value)
2137 }
2138 }
2139 XsdDatatypeKind::Notation => {
2140 !value.is_empty()
2142 }
2143 XsdDatatypeKind::Nmtoken => !value.is_empty() && value.chars().all(is_name_char),
2144 XsdDatatypeKind::Nmtokens => {
2145 !value.is_empty()
2146 && value
2147 .split_whitespace()
2148 .all(|t| !t.is_empty() && t.chars().all(is_name_char))
2149 }
2150 XsdDatatypeKind::Idrefs | XsdDatatypeKind::Entities => {
2151 !value.is_empty() && value.split_whitespace().all(is_ncname)
2152 }
2153 XsdDatatypeKind::FacetPattern
2155 | XsdDatatypeKind::FacetEnumeration
2156 | XsdDatatypeKind::FacetMinInclusive
2157 | XsdDatatypeKind::FacetMaxInclusive
2158 | XsdDatatypeKind::FacetMinExclusive
2159 | XsdDatatypeKind::FacetMaxExclusive
2160 | XsdDatatypeKind::FacetMinLength
2161 | XsdDatatypeKind::FacetMaxLength
2162 | XsdDatatypeKind::FacetLength
2163 | XsdDatatypeKind::FacetWhiteSpace
2164 | XsdDatatypeKind::FacetFractionDigits
2165 | XsdDatatypeKind::FacetTotalDigits => true,
2166 }
2167}
2168
2169fn is_ncname(value: &str) -> bool {
2171 if value.is_empty() {
2172 return false;
2173 }
2174 let first = value.chars().next().unwrap();
2175 if !is_name_start_char(first) || first == ':' {
2176 return false;
2177 }
2178 value.chars().skip(1).all(|c| is_name_char(c) && c != ':')
2179}
2180
2181pub fn xsd_validate(schema: &XsdSchema, doc: &str) -> Result<(), Vec<String>> {
2198 let doc_ptr = unsafe {
2199 crate::abi::exports_xml2::xmlReadMemory(
2200 doc.as_ptr() as *const c_char,
2201 doc.len() as c_int,
2202 c"doc.xml".as_ptr() as *const c_char,
2203 ptr::null(),
2204 0,
2205 )
2206 };
2207
2208 if doc_ptr.is_null() {
2209 return Err(vec!["Failed to parse XML document".to_string()]);
2210 }
2211
2212 let mut ctxt = XsdValidCtxt::new();
2213 ctxt.schema = Some(schema.clone());
2214
2215 let result = unsafe { xsd_validate_doc(schema, doc_ptr, &mut ctxt) };
2216
2217 unsafe {
2218 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
2219 }
2220
2221 if result {
2222 Ok(())
2223 } else {
2224 Err(ctxt.errors)
2225 }
2226}
2227
2228unsafe fn xsd_validate_doc(schema: &XsdSchema, doc: *mut _xmlDoc, ctxt: &mut XsdValidCtxt) -> bool {
2234 unsafe {
2235 let root = (*doc).children;
2236 if root.is_null() {
2237 ctxt.errors.push("Document has no root element".to_string());
2238 ctxt.nb_errors += 1;
2239 return false;
2240 }
2241
2242 let mut root_elem = root;
2244 while !root_elem.is_null() && (*root_elem).type_ != XML_ELEMENT_NODE as c_int {
2245 root_elem = (*root_elem).next;
2246 }
2247
2248 if root_elem.is_null() {
2249 ctxt.errors.push("Document has no root element".to_string());
2250 ctxt.nb_errors += 1;
2251 return false;
2252 }
2253
2254 let root_name = get_node_qname(root_elem);
2256 let root_local = get_node_local_name(root_elem);
2257 let root_ns = get_node_ns_href(root_elem);
2258 let root_ns_deref = root_ns.as_deref();
2259
2260 let global_elem = schema.components.iter().find(|c| {
2268 c.component_type == XsdComponentType::Element
2269 && c.name.as_deref() == Some(root_local.as_str())
2270 && c.target_namespace.as_deref() == root_ns_deref
2271 });
2272
2273 if let Some(global) = global_elem {
2274 xsd_validate_element(global, root_elem, schema, ctxt)
2275 } else {
2276 ctxt.errors.push(format!(
2280 "Element '{}': No matching global declaration available for the validation root.",
2281 root_name
2282 ));
2283 ctxt.nb_errors += 1;
2284 false
2285 }
2286 }
2287}
2288
2289pub(crate) unsafe fn xsd_validate_doc_compiled(
2301 schema: *mut c_void,
2302 doc: *mut _xmlDoc,
2303 create_defaults: bool,
2304) -> (bool, Vec<String>) {
2305 unsafe {
2306 if schema.is_null() || doc.is_null() {
2307 return (false, Vec::new());
2308 }
2309 let schema_ref = &*(schema as *const XsdSchema);
2310 let mut ctxt = XsdValidCtxt::new();
2311 ctxt.create_defaults = create_defaults;
2312 let valid = xsd_validate_doc(schema_ref, doc, &mut ctxt);
2313 (valid, ctxt.errors)
2314 }
2315}
2316
2317fn element_decl_ns(comp: &XsdComponent, schema: &XsdSchema) -> Option<String> {
2325 if let Some(ref ns) = comp.target_namespace {
2326 return Some(ns.clone());
2327 }
2328 let qualified = comp.form.as_deref() == Some("qualified")
2329 || (comp.form.is_none() && schema.element_form_default.as_deref() == Some("qualified"));
2330 if qualified {
2331 schema.target_namespace.clone()
2332 } else {
2333 None
2334 }
2335}
2336
2337fn xsd_validate_element(
2343 component: &XsdComponent,
2344 node: *mut _xmlNode,
2345 schema: &XsdSchema,
2346 ctxt: &mut XsdValidCtxt,
2347) -> bool {
2348 unsafe {
2349 let mut valid = true;
2350
2351 let node_name = get_node_qname(node);
2353 let node_local = get_node_local_name(node);
2354 let node_ns = get_node_ns_href(node);
2355 let decl_ns = element_decl_ns(component, schema);
2356
2357 if let Some(ref comp_name) = component.name {
2367 if comp_name != &node_local || node_ns.as_deref() != decl_ns.as_deref() {
2368 ctxt.errors.push(format!(
2369 "Element '{}' does not match expected '{}'",
2370 node_name, comp_name
2371 ));
2372 ctxt.nb_errors += 1;
2373 return false;
2374 }
2375 }
2376
2377 let type_comp = component.children.iter().find(|c| {
2379 c.component_type == XsdComponentType::ComplexType
2380 || c.component_type == XsdComponentType::SimpleType
2381 });
2382
2383 if let Some(tc) = type_comp {
2384 match tc.component_type {
2385 XsdComponentType::ComplexType => {
2386 valid &= xsd_validate_complex_type(tc, node, schema, ctxt);
2387 }
2388 XsdComponentType::SimpleType => {
2389 let text = get_node_text(node);
2390 if let Some(ref dt) = tc.datatype {
2391 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2392 ctxt.errors.push(format!(
2393 "Element '{}' has invalid value '{}' for type '{:?}'",
2394 node_name, text, dt
2395 ));
2396 ctxt.nb_errors += 1;
2397 valid = false;
2398 }
2399 }
2400 }
2401 _ => {}
2402 }
2403 } else if let Some(ref dt) = component.datatype {
2404 let text = get_node_text(node);
2406 if !xsd_validate_datatype(dt, &text, &component.facets) {
2407 ctxt.errors.push(format!(
2408 "Element '{}' has invalid value '{}' for type '{:?}'",
2409 node_name, text, dt
2410 ));
2411 ctxt.nb_errors += 1;
2412 valid = false;
2413 }
2414 } else if let Some(ref base_name) = component.base {
2415 if let Some(named) = schema.components.iter().find(|c| {
2428 let ct = c.component_type;
2429 (ct == XsdComponentType::ComplexType || ct == XsdComponentType::SimpleType)
2430 && c.name.as_deref() == Some(xsd_qname_local(base_name))
2431 }) {
2432 match named.component_type {
2433 XsdComponentType::ComplexType => {
2434 valid &= xsd_validate_complex_type(named, node, schema, ctxt);
2435 }
2436 XsdComponentType::SimpleType => {
2437 let text = get_node_text(node);
2438 if let Some(ref dt) = named.datatype {
2439 if !xsd_validate_datatype(dt, &text, &named.facets) {
2440 ctxt.errors.push(format!(
2441 "Element '{}' has invalid value '{}' for type '{}'",
2442 node_name, text, base_name
2443 ));
2444 ctxt.nb_errors += 1;
2445 valid = false;
2446 }
2447 }
2448 }
2449 _ => {}
2450 }
2451 } else {
2452 valid &= xsd_validate_content(component, node, schema, ctxt);
2455 }
2456 } else {
2457 valid &= xsd_validate_content(component, node, schema, ctxt);
2459 }
2460
2461 valid
2462 }
2463}
2464
2465fn xsd_validate_complex_type(
2471 component: &XsdComponent,
2472 node: *mut _xmlNode,
2473 schema: &XsdSchema,
2474 ctxt: &mut XsdValidCtxt,
2475) -> bool {
2476 {
2477 let mut valid = true;
2478
2479 for attr in &component.attributes {
2481 match attr.component_type {
2482 XsdComponentType::Attribute => {
2483 if ctxt.create_defaults {
2489 unsafe { inject_default_attribute(attr, node) };
2490 }
2491 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2492 }
2493 XsdComponentType::AnyAttribute => {
2494 }
2496 _ => {}
2497 }
2498 }
2499
2500 for child in &component.children {
2502 match child.component_type {
2503 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2504 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2505 }
2506 XsdComponentType::Restriction | XsdComponentType::Extension => {
2507 valid &= xsd_validate_restriction_extension(child, node, schema, ctxt);
2509 }
2510 XsdComponentType::Any => {
2511 }
2513 _ => {}
2514 }
2515 }
2516
2517 valid
2518 }
2519}
2520
2521unsafe fn inject_default_attribute(component: &XsdComponent, node: *mut _xmlNode) {
2530 unsafe {
2531 let Some(ref name) = component.name else {
2532 return;
2533 };
2534 if name.is_empty() || component.ref_name.is_some() {
2535 return;
2536 }
2537 let value = match (&component.fixed_value, &component.default_value) {
2538 (Some(f), _) => f.clone(),
2539 (None, Some(d)) => d.clone(),
2540 (None, None) => return,
2541 };
2542 if component.form.as_deref() == Some("qualified") {
2544 return;
2545 }
2546 if get_attr(node, name).is_some() {
2547 return;
2548 }
2549 let (Ok(n), Ok(v)) = (
2550 std::ffi::CString::new(name.as_str()),
2551 std::ffi::CString::new(value.as_str()),
2552 ) else {
2553 return;
2554 };
2555 crate::abi::exports_xml2::xmlSetProp(
2556 node,
2557 n.as_ptr() as *const crate::abi::types::xmlChar,
2558 v.as_ptr() as *const crate::abi::types::xmlChar,
2559 );
2560 }
2561}
2562
2563pub fn xsd_validate_model_group(
2569 component: &XsdComponent,
2570 node: *mut _xmlNode,
2571 schema: &XsdSchema,
2572 ctxt: &mut XsdValidCtxt,
2573) -> bool {
2574 unsafe {
2575 let mut valid = true;
2576
2577 let mut child_nodes: Vec<*mut _xmlNode> = Vec::new();
2579 let mut child = (*node).children;
2580 while !child.is_null() {
2581 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2582 child_nodes.push(child);
2583 }
2584 child = (*child).next;
2585 }
2586
2587 let mut content_bad = false;
2588
2589 match component.component_type {
2590 XsdComponentType::Sequence => {
2591 let mut child_idx = 0;
2593 let mut part_counts: Vec<i32> = vec![0; component.children.len()];
2594 for (k, part) in component.children.iter().enumerate() {
2595 let min = part.min_occurs;
2596 let max = part.max_occurs;
2597 let match_name = part.name.as_deref().unwrap_or("");
2598 let match_ref = part.ref_name.as_deref().unwrap_or("");
2599
2600 let mut count = 0;
2601 while child_idx < child_nodes.len() && (max == -1 || count < max) {
2602 let child_node = child_nodes[child_idx];
2603 let child_name = get_node_qname(child_node);
2604
2605 if part.component_type == XsdComponentType::Any
2606 || (!match_name.is_empty() && child_name == match_name)
2607 || (!match_ref.is_empty() && child_name == match_ref)
2608 {
2609 if let Some(ref dt) = part.datatype {
2616 let text = get_node_text(child_node);
2617 if !xsd_validate_datatype(dt, &text, &part.facets) {
2618 let type_name = datatype_kind_qname(dt);
2619 ctxt.errors.push(format!(
2620 "Element '{}': '{}' is not a valid value of the atomic type '{}'.",
2621 child_name, text, type_name
2622 ));
2623 ctxt.nb_errors += 1;
2624 valid = false;
2625 }
2626 }
2627 if part.component_type == XsdComponentType::Element
2633 && (part.datatype.is_none())
2634 && (!part.children.is_empty() || part.base.is_some())
2635 {
2636 valid &= xsd_validate_element(part, child_node, schema, ctxt);
2637 }
2638 count += 1;
2639 child_idx += 1;
2640 } else if count >= min {
2641 break;
2642 } else {
2643 ctxt.errors.push(format!(
2652 "Element '{}': This element is not expected. Expected is ( {} ).",
2653 child_name, match_name
2654 ));
2655 ctxt.nb_errors += 1;
2656 valid = false;
2657 content_bad = true;
2658 break;
2659 }
2660 }
2661 part_counts[k] = count;
2662 if content_bad {
2663 break;
2664 }
2665
2666 if count < min {
2667 let mut expected: Vec<String> = Vec::new();
2674 for (j, p) in component.children.iter().enumerate().take(k + 1) {
2675 let name = p.name.as_deref().unwrap_or("");
2676 if name.is_empty() {
2677 continue;
2678 }
2679 let still_expected = if j == k {
2680 true
2681 } else {
2682 let cj = part_counts[j];
2683 p.max_occurs == -1 || cj < p.max_occurs.max(0)
2684 };
2685 if still_expected {
2686 expected.push(name.to_string());
2687 }
2688 }
2689 let node_name = get_node_qname(node);
2690 if expected.len() > 1 {
2691 ctxt.errors.push(format!(
2692 "Element '{}': Missing child element(s). Expected is one of ( {} ).",
2693 node_name,
2694 expected.join(", ")
2695 ));
2696 } else if expected.len() == 1 {
2697 ctxt.errors.push(format!(
2698 "Element '{}': Missing child element(s). Expected is ( {} ).",
2699 node_name, expected[0]
2700 ));
2701 } else {
2702 ctxt.errors.push(format!(
2703 "Element '{}': Missing child element(s).",
2704 node_name
2705 ));
2706 }
2707 ctxt.nb_errors += 1;
2708 valid = false;
2709 }
2710 }
2711
2712 if content_bad {
2714 } else if child_idx < child_nodes.len() {
2718 let extra = get_node_qname(child_nodes[child_idx]);
2719 ctxt.errors
2720 .push(format!("Unexpected element '{}' in sequence", extra));
2721 ctxt.nb_errors += 1;
2722 valid = false;
2723 }
2724 }
2725 XsdComponentType::Choice => {
2726 let mut matched = false;
2728 for child_node in &child_nodes {
2729 let child_name = get_node_qname(*child_node);
2730 for part in &component.children {
2731 let match_name = part.name.as_deref().unwrap_or("");
2732 let match_ref = part.ref_name.as_deref().unwrap_or("");
2733
2734 if part.component_type == XsdComponentType::Any {
2735 matched = true;
2736 } else if (!match_name.is_empty() && child_name == match_name)
2737 || (!match_ref.is_empty() && child_name == match_ref)
2738 {
2739 matched = true;
2740 break;
2741 }
2742 }
2743 if !matched {
2744 ctxt.errors
2745 .push(format!("Element '{}' is not valid in choice", child_name));
2746 ctxt.nb_errors += 1;
2747 valid = false;
2748 }
2749 matched = false; }
2751 }
2752 XsdComponentType::All => {
2753 for child_node in &child_nodes {
2755 let child_name = get_node_qname(*child_node);
2756 let mut matched = false;
2757 for part in &component.children {
2758 let match_name = part.name.as_deref().unwrap_or("");
2759 if !match_name.is_empty() && child_name == match_name {
2760 matched = true;
2761 break;
2762 }
2763 }
2764 if !matched {
2765 ctxt.errors.push(format!(
2766 "Element '{}' is not valid in all group",
2767 child_name
2768 ));
2769 ctxt.nb_errors += 1;
2770 valid = false;
2771 }
2772 }
2773 }
2774 _ => {}
2775 }
2776
2777 valid
2778 }
2779}
2780
2781fn xsd_validate_restriction_extension(
2787 component: &XsdComponent,
2788 node: *mut _xmlNode,
2789 schema: &XsdSchema,
2790 ctxt: &mut XsdValidCtxt,
2791) -> bool {
2792 unsafe {
2793 let mut valid = true;
2794
2795 for attr in &component.attributes {
2797 if attr.component_type == XsdComponentType::Attribute {
2798 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2799 }
2800 }
2801
2802 for child in &component.children {
2804 match child.component_type {
2805 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2806 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2807 }
2808 _ => {}
2809 }
2810 }
2811
2812 if let Some(ref dt) = component.datatype {
2814 let text = get_node_text(node);
2815 if !xsd_validate_datatype(dt, &text, &component.facets) {
2816 let node_name = get_node_qname(node);
2817 ctxt.errors.push(format!(
2818 "Element '{}' has invalid value '{}' for type '{:?}'",
2819 node_name, text, dt
2820 ));
2821 ctxt.nb_errors += 1;
2822 valid = false;
2823 }
2824 }
2825
2826 valid
2827 }
2828}
2829
2830fn xsd_validate_attribute(
2836 component: &XsdComponent,
2837 node: *mut _xmlNode,
2838 _schema: &XsdSchema,
2839 ctxt: &mut XsdValidCtxt,
2840) -> bool {
2841 unsafe {
2842 let attr_name = component.name.as_deref().unwrap_or("");
2843 if attr_name.is_empty() {
2844 return true;
2845 }
2846
2847 let attr_value = get_attr(node, attr_name);
2849
2850 let is_required = component.min_occurs > 0;
2851
2852 match attr_value {
2853 Some(ref val) => {
2854 if let Some(ref dt) = component.datatype {
2856 if !xsd_validate_datatype(dt, val, &component.facets) {
2857 ctxt.errors.push(format!(
2858 "Attribute '{}' has invalid value '{}' for type '{:?}'",
2859 attr_name, val, dt
2860 ));
2861 ctxt.nb_errors += 1;
2862 return false;
2863 }
2864 }
2865 true
2866 }
2867 None => {
2868 if is_required {
2869 ctxt.errors
2870 .push(format!("Required attribute '{}' is missing", attr_name));
2871 ctxt.nb_errors += 1;
2872 false
2873 } else {
2874 true
2875 }
2876 }
2877 }
2878 }
2879}
2880
2881fn xsd_validate_content(
2887 component: &XsdComponent,
2888 node: *mut _xmlNode,
2889 schema: &XsdSchema,
2890 ctxt: &mut XsdValidCtxt,
2891) -> bool {
2892 {
2893 let mut valid = true;
2894
2895 for child_comp in &component.children {
2896 match child_comp.component_type {
2897 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2898 valid &= xsd_validate_model_group(child_comp, node, schema, ctxt);
2899 }
2900 XsdComponentType::Element => {
2901 valid &= xsd_validate_element_inline(child_comp, node, schema, ctxt);
2903 }
2904 _ => {}
2905 }
2906 }
2907
2908 valid
2909 }
2910}
2911
2912fn xsd_validate_element_inline(
2918 component: &XsdComponent,
2919 node: *mut _xmlNode,
2920 schema: &XsdSchema,
2921 ctxt: &mut XsdValidCtxt,
2922) -> bool {
2923 unsafe {
2924 let mut valid = true;
2925 let mut child = (*node).children;
2926
2927 while !child.is_null() {
2928 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2929 let child_name = get_node_qname(child);
2930
2931 let match_name = component.name.as_deref().unwrap_or("");
2932 let match_ref = component.ref_name.as_deref().unwrap_or("");
2933
2934 if (!match_name.is_empty() && child_name == match_name)
2935 || (!match_ref.is_empty() && child_name == match_ref)
2936 {
2937 let type_comp = component.children.iter().find(|c| {
2939 c.component_type == XsdComponentType::ComplexType
2940 || c.component_type == XsdComponentType::SimpleType
2941 });
2942
2943 if let Some(tc) = type_comp {
2944 match tc.component_type {
2945 XsdComponentType::ComplexType => {
2946 valid &= xsd_validate_complex_type(tc, child, schema, ctxt);
2947 }
2948 XsdComponentType::SimpleType => {
2949 let text = get_node_text(child);
2950 if let Some(ref dt) = tc.datatype {
2951 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2952 ctxt.errors.push(format!(
2953 "Element '{}' has invalid value '{}'",
2954 child_name, text
2955 ));
2956 ctxt.nb_errors += 1;
2957 valid = false;
2958 }
2959 }
2960 }
2961 _ => {}
2962 }
2963 } else if let Some(ref base_name) = component.base {
2964 if let Some(named) = schema.components.iter().find(|c| {
2970 let ct = c.component_type;
2971 (ct == XsdComponentType::ComplexType
2972 || ct == XsdComponentType::SimpleType)
2973 && c.name.as_deref() == Some(xsd_qname_local(base_name))
2974 }) {
2975 match named.component_type {
2976 XsdComponentType::ComplexType => {
2977 valid &= xsd_validate_complex_type(named, child, schema, ctxt);
2978 }
2979 XsdComponentType::SimpleType => {
2980 let text = get_node_text(child);
2981 if let Some(ref dt) = named.datatype {
2982 if !xsd_validate_datatype(dt, &text, &named.facets) {
2983 ctxt.errors.push(format!(
2984 "Element '{}' has invalid value '{}'",
2985 child_name, text
2986 ));
2987 ctxt.nb_errors += 1;
2988 valid = false;
2989 }
2990 }
2991 }
2992 _ => {}
2993 }
2994 }
2995 }
2996 }
2997 }
2998 child = (*child).next;
2999 }
3000
3001 valid
3002 }
3003}
3004
3005unsafe fn get_node_local_name(node: *mut _xmlNode) -> String {
3012 if node.is_null() {
3013 return String::new();
3014 }
3015 unsafe {
3016 let name = (*node).name;
3017 if name.is_null() {
3018 return String::new();
3019 }
3020 let mut len = 0;
3021 while *name.add(len) != 0 {
3022 len += 1;
3023 }
3024 let slice = std::slice::from_raw_parts(name, len);
3025 String::from_utf8_lossy(slice).to_string()
3026 }
3027}
3028
3029unsafe fn get_node_ns_href(node: *mut _xmlNode) -> Option<String> {
3036 if node.is_null() {
3037 return None;
3038 }
3039 unsafe {
3040 let ns = (*node).ns;
3041 if ns.is_null() {
3042 return None;
3043 }
3044 let href = (*ns).href;
3045 if href.is_null() {
3046 return None;
3047 }
3048 let mut len = 0;
3049 while *href.add(len) != 0 {
3050 len += 1;
3051 }
3052 let slice = std::slice::from_raw_parts(href, len);
3053 Some(String::from_utf8_lossy(slice).to_string())
3054 }
3055}
3056
3057fn xsd_element_decl_matches(comp: &XsdComponent, node_local: &str, node_ns: Option<&str>) -> bool {
3064 comp.component_type == XsdComponentType::Element
3065 && comp.name.as_deref() == Some(node_local)
3066 && comp.target_namespace.as_deref() == node_ns
3067}
3068
3069fn xsd_qname_local(name: &str) -> &str {
3073 match name.rsplit_once(':') {
3074 Some((_, local)) => local,
3075 None => name,
3076 }
3077}
3078
3079unsafe fn get_node_qname(node: *mut _xmlNode) -> String {
3086 if node.is_null() {
3087 return String::new();
3088 }
3089 unsafe {
3090 let ns = (*node).ns;
3092 let prefix = if !ns.is_null() && !(*ns).prefix.is_null() {
3093 let mut len = 0;
3094 while *(*ns).prefix.add(len) != 0 {
3095 len += 1;
3096 }
3097 let slice = std::slice::from_raw_parts((*ns).prefix, len);
3098 if let Ok(s) = std::str::from_utf8(slice) {
3099 format!("{}:", s)
3100 } else {
3101 String::new()
3102 }
3103 } else {
3104 String::new()
3105 };
3106
3107 let name = (*node).name;
3108 if name.is_null() {
3109 return String::new();
3110 }
3111 let mut len = 0;
3112 while *name.add(len) != 0 {
3113 len += 1;
3114 }
3115 let slice = std::slice::from_raw_parts(name, len);
3116 if let Ok(s) = std::str::from_utf8(slice) {
3117 format!("{}{}", prefix, s)
3118 } else {
3119 String::new()
3120 }
3121 }
3122}
3123
3124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3144pub(crate) enum XsdParseFail {
3145 Resource,
3148 Document,
3151}
3152
3153pub(crate) struct XsdParserCtxt {
3154 pub(crate) schema: Option<XsdSchema>,
3156 pub(crate) fail: Option<XsdParseFail>,
3158 pub(crate) url: Option<String>,
3162 pub(crate) mem: bool,
3164}
3165
3166impl XsdParserCtxt {
3167 const fn empty() -> Self {
3168 Self {
3169 schema: None,
3170 fail: None,
3171 url: None,
3172 mem: false,
3173 }
3174 }
3175}
3176
3177#[no_mangle]
3189pub unsafe extern "C" fn xmlSchemaNewParserCtxt(url: *const c_char) -> *mut c_void {
3190 if url.is_null() {
3191 return Box::into_raw(Box::new(XsdParserCtxt::empty())) as *mut c_void;
3193 }
3194
3195 let url_str = unsafe {
3196 let mut len = 0;
3197 while *url.add(len) != 0 {
3198 len += 1;
3199 }
3200 let slice = std::slice::from_raw_parts(url as *const u8, len);
3201 String::from_utf8_lossy(slice).to_string()
3202 };
3203
3204 let (schema, fail) = if url_str.is_empty() {
3213 (None, Some(XsdParseFail::Resource))
3214 } else {
3215 let url_c = std::ffi::CString::new(url_str.clone()).ok();
3216 let mut parsed: Option<XsdSchema> = None;
3217 let mut failed = XsdParseFail::Document;
3218 if let Some(c) = url_c {
3219 let doc = crate::abi::exports_xml2::xmlParseFile(c.as_ptr());
3220 if doc.is_null() {
3221 failed = if std::fs::metadata(&url_str).is_err() {
3226 XsdParseFail::Resource
3227 } else {
3228 XsdParseFail::Document
3229 };
3230 } else {
3231 let result = unsafe { xsd_parse_schema_doc(doc) };
3232 unsafe {
3233 crate::abi::exports_xml2::xmlFreeDoc(doc);
3234 }
3235 match result {
3236 Ok(s) => parsed = Some(s),
3237 Err(_) => failed = XsdParseFail::Document,
3238 }
3239 }
3240 } else {
3241 failed = XsdParseFail::Resource;
3242 }
3243 if parsed.is_some() {
3244 (parsed, None)
3245 } else {
3246 (None, Some(failed))
3247 }
3248 };
3249 Box::into_raw(Box::new(XsdParserCtxt {
3250 schema,
3251 fail,
3252 url: Some(url_str),
3253 mem: false,
3254 })) as *mut c_void
3255}
3256
3257#[no_mangle]
3269pub unsafe extern "C" fn xmlSchemaNewMemParserCtxt(
3270 buffer: *const c_char,
3271 size: c_int,
3272) -> *mut c_void {
3273 if buffer.is_null() || size <= 0 {
3274 return ptr::null_mut();
3275 }
3276
3277 let buf_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, size as usize) };
3285 let doc = unsafe {
3286 crate::abi::exports_xml2::xmlReadMemory(
3287 buf_slice.as_ptr() as *const c_char,
3288 buf_slice.len() as c_int,
3289 ptr::null(),
3290 ptr::null(),
3291 0,
3292 )
3293 };
3294 let (schema, fail) = if doc.is_null() {
3295 (None, Some(XsdParseFail::Document))
3296 } else {
3297 let result = unsafe { xsd_parse_schema_doc(doc) };
3298 unsafe {
3299 crate::abi::exports_xml2::xmlFreeDoc(doc);
3300 }
3301 match result {
3302 Ok(s) => (Some(s), None),
3303 Err(_) => (None, Some(XsdParseFail::Document)),
3304 }
3305 };
3306 Box::into_raw(Box::new(XsdParserCtxt {
3307 schema,
3308 fail,
3309 url: None,
3310 mem: true,
3311 })) as *mut c_void
3312}
3313
3314#[no_mangle]
3326pub unsafe extern "C" fn xmlSchemaParse(ctxt: *mut c_void) -> *mut c_void {
3327 if ctxt.is_null() {
3328 return ptr::null_mut();
3329 }
3330
3331 let pctxt = unsafe { &*ctxt.cast::<XsdParserCtxt>() };
3342 match &pctxt.schema {
3343 Some(schema) => Box::into_raw(Box::new(schema.clone())) as *mut c_void,
3344 None => {
3345 let msg = match pctxt.fail {
3346 Some(XsdParseFail::Resource) => pctxt
3347 .url
3348 .as_deref()
3349 .map(|u| format!("Failed to locate the main schema resource at '{}'.\n", u)),
3350 Some(XsdParseFail::Document) => Some(format!(
3351 "Failed to parse the XML resource '{}'.\n",
3352 pctxt
3353 .url
3354 .as_deref()
3355 .unwrap_or(if pctxt.mem { "in_memory_buffer" } else { "" })
3356 )),
3357 None => None,
3358 };
3359 if let Some(m) = msg {
3360 crate::abi::exports_schema::dispatch_parser_error(ctxt as usize, &m);
3361 }
3362 ptr::null_mut()
3363 }
3364 }
3365}
3366
3367#[no_mangle]
3379pub unsafe extern "C" fn xmlSchemaFree(schema: *mut c_void) {
3380 if schema.is_null() {
3381 return;
3382 }
3383 unsafe {
3385 let _ = Box::from_raw(schema as *mut XsdSchema);
3386 }
3387}
3388
3389#[no_mangle]
3404pub unsafe extern "C" fn xmlSchemaValidateDoc(ctxt: *mut c_void, doc: *mut _xmlDoc) -> c_int {
3405 if ctxt.is_null() || doc.is_null() {
3406 return -1;
3407 }
3408
3409 unsafe {
3410 let valid_ctxt = &mut *(ctxt as *mut XsdValidCtxt);
3411 let schema = match &valid_ctxt.schema {
3412 Some(s) => s,
3413 None => return -1,
3414 };
3415
3416 let mut temp_ctxt = XsdValidCtxt::new();
3417 temp_ctxt.schema = Some(schema.clone());
3418 temp_ctxt.create_defaults =
3423 crate::abi::exports_schema::valid_ctxt_options(ctxt as usize) & (1 << 0) != 0;
3424
3425 let valid = xsd_validate_doc(schema, doc, &mut temp_ctxt);
3426
3427 if valid {
3428 0
3429 } else {
3430 valid_ctxt.errors = temp_ctxt.errors;
3431 valid_ctxt.nb_errors = temp_ctxt.nb_errors;
3432 crate::abi::exports_schema::dispatch_valid_errors(ctxt as usize, &valid_ctxt.errors);
3438 temp_ctxt.nb_errors
3439 }
3440 }
3441}
3442
3443#[no_mangle]
3455pub unsafe extern "C" fn xmlSchemaFreeParserCtxt(ctxt: *mut c_void) {
3456 if ctxt.is_null() {
3457 return;
3458 }
3459 unsafe {
3462 let _ = Box::from_raw(ctxt as *mut XsdParserCtxt);
3463 }
3464}
3465
3466#[no_mangle]
3478pub unsafe extern "C" fn xmlSchemaFreeValidCtxt(ctxt: *mut c_void) {
3479 if ctxt.is_null() {
3480 return;
3481 }
3482 unsafe {
3484 let _ = Box::from_raw(ctxt as *mut XsdValidCtxt);
3485 }
3486}
3487
3488#[no_mangle]
3500pub unsafe extern "C" fn xmlSchemaNewValidCtxt(schema: *mut c_void) -> *mut c_void {
3501 let mut ctxt = XsdValidCtxt::new();
3502
3503 if !schema.is_null() {
3504 unsafe {
3506 let schema_ref = &*(schema as *const XsdSchema);
3507 ctxt.schema = Some(schema_ref.clone());
3508 }
3509 }
3510
3511 let boxed = Box::new(ctxt);
3512 Box::into_raw(boxed) as *mut c_void
3513}
3514
3515#[cfg(test)]
3520mod tests {
3521 use super::*;
3522
3523 #[test]
3526 fn test_validate_string() {
3527 assert!(xsd_validate_datatype(
3528 &XsdDatatypeKind::String,
3529 "hello",
3530 &[]
3531 ));
3532 assert!(xsd_validate_datatype(&XsdDatatypeKind::String, "", &[]));
3533 }
3534
3535 #[test]
3536 fn test_validate_boolean() {
3537 assert!(xsd_validate_datatype(
3538 &XsdDatatypeKind::Boolean,
3539 "true",
3540 &[]
3541 ));
3542 assert!(xsd_validate_datatype(
3543 &XsdDatatypeKind::Boolean,
3544 "false",
3545 &[]
3546 ));
3547 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "1", &[]));
3548 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "0", &[]));
3549 assert!(!xsd_validate_datatype(
3550 &XsdDatatypeKind::Boolean,
3551 "yes",
3552 &[]
3553 ));
3554 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Boolean, "no", &[]));
3555 }
3556
3557 #[test]
3558 fn test_validate_integer() {
3559 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "42", &[]));
3560 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "-42", &[]));
3561 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "+42", &[]));
3562 assert!(!xsd_validate_datatype(
3563 &XsdDatatypeKind::Integer,
3564 "12.5",
3565 &[]
3566 ));
3567 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Integer, "", &[]));
3568 assert!(!xsd_validate_datatype(
3569 &XsdDatatypeKind::Integer,
3570 "abc",
3571 &[]
3572 ));
3573 }
3574
3575 #[test]
3576 fn test_validate_decimal() {
3577 assert!(xsd_validate_datatype(&XsdDatatypeKind::Decimal, "42", &[]));
3578 assert!(xsd_validate_datatype(
3579 &XsdDatatypeKind::Decimal,
3580 "12.5",
3581 &[]
3582 ));
3583 assert!(xsd_validate_datatype(
3584 &XsdDatatypeKind::Decimal,
3585 "-3.14",
3586 &[]
3587 ));
3588 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Decimal, "", &[]));
3589 }
3590
3591 #[test]
3592 fn test_validate_float() {
3593 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "3.14", &[]));
3594 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "INF", &[]));
3595 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "-INF", &[]));
3596 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "NaN", &[]));
3597 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Float, "", &[]));
3598 }
3599
3600 #[test]
3601 fn test_validate_positive_integer() {
3602 assert!(xsd_validate_datatype(
3603 &XsdDatatypeKind::PositiveInteger,
3604 "1",
3605 &[]
3606 ));
3607 assert!(xsd_validate_datatype(
3608 &XsdDatatypeKind::PositiveInteger,
3609 "100",
3610 &[]
3611 ));
3612 assert!(!xsd_validate_datatype(
3613 &XsdDatatypeKind::PositiveInteger,
3614 "0",
3615 &[]
3616 ));
3617 assert!(!xsd_validate_datatype(
3618 &XsdDatatypeKind::PositiveInteger,
3619 "-1",
3620 &[]
3621 ));
3622 }
3623
3624 #[test]
3625 fn test_validate_non_negative_integer() {
3626 assert!(xsd_validate_datatype(
3627 &XsdDatatypeKind::NonNegativeInteger,
3628 "0",
3629 &[]
3630 ));
3631 assert!(xsd_validate_datatype(
3632 &XsdDatatypeKind::NonNegativeInteger,
3633 "42",
3634 &[]
3635 ));
3636 assert!(!xsd_validate_datatype(
3637 &XsdDatatypeKind::NonNegativeInteger,
3638 "-1",
3639 &[]
3640 ));
3641 }
3642
3643 #[test]
3644 fn test_validate_int_range() {
3645 assert!(xsd_validate_datatype(
3646 &XsdDatatypeKind::Int,
3647 "2147483647",
3648 &[]
3649 ));
3650 assert!(xsd_validate_datatype(
3651 &XsdDatatypeKind::Int,
3652 "-2147483648",
3653 &[]
3654 ));
3655 assert!(!xsd_validate_datatype(
3656 &XsdDatatypeKind::Int,
3657 "2147483648",
3658 &[]
3659 ));
3660 }
3661
3662 #[test]
3663 fn test_validate_short_range() {
3664 assert!(xsd_validate_datatype(&XsdDatatypeKind::Short, "32767", &[]));
3665 assert!(xsd_validate_datatype(
3666 &XsdDatatypeKind::Short,
3667 "-32768",
3668 &[]
3669 ));
3670 assert!(!xsd_validate_datatype(
3671 &XsdDatatypeKind::Short,
3672 "32768",
3673 &[]
3674 ));
3675 }
3676
3677 #[test]
3678 fn test_validate_byte_range() {
3679 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "127", &[]));
3680 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "-128", &[]));
3681 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Byte, "128", &[]));
3682 }
3683
3684 #[test]
3685 fn test_validate_date_time() {
3686 assert!(xsd_validate_datatype(
3687 &XsdDatatypeKind::DateTime,
3688 "2023-01-15T10:30:00",
3689 &[]
3690 ));
3691 assert!(!xsd_validate_datatype(
3692 &XsdDatatypeKind::DateTime,
3693 "not-a-date",
3694 &[]
3695 ));
3696 }
3697
3698 #[test]
3699 fn test_validate_date() {
3700 assert!(xsd_validate_datatype(
3701 &XsdDatatypeKind::Date,
3702 "2023-01-15",
3703 &[]
3704 ));
3705 assert!(!xsd_validate_datatype(
3706 &XsdDatatypeKind::Date,
3707 "2023/01/15",
3708 &[]
3709 ));
3710 }
3711
3712 #[test]
3713 fn test_validate_time() {
3714 assert!(xsd_validate_datatype(
3715 &XsdDatatypeKind::Time,
3716 "10:30:00",
3717 &[]
3718 ));
3719 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Time, "10:30", &[]));
3720 }
3721
3722 #[test]
3723 fn test_validate_hex_binary() {
3724 assert!(xsd_validate_datatype(
3725 &XsdDatatypeKind::HexBinary,
3726 "0FA1",
3727 &[]
3728 ));
3729 assert!(xsd_validate_datatype(&XsdDatatypeKind::HexBinary, "", &[]));
3730 assert!(!xsd_validate_datatype(
3731 &XsdDatatypeKind::HexBinary,
3732 "0FG1",
3733 &[]
3734 ));
3735 assert!(!xsd_validate_datatype(
3736 &XsdDatatypeKind::HexBinary,
3737 "0FA",
3738 &[]
3739 ));
3740 }
3741
3742 #[test]
3743 fn test_validate_base64() {
3744 assert!(xsd_validate_datatype(
3745 &XsdDatatypeKind::Base64Binary,
3746 "SGVsbG8=",
3747 &[]
3748 ));
3749 assert!(xsd_validate_datatype(
3750 &XsdDatatypeKind::Base64Binary,
3751 "",
3752 &[]
3753 ));
3754 assert!(!xsd_validate_datatype(
3755 &XsdDatatypeKind::Base64Binary,
3756 "Hello World!",
3757 &[]
3758 ));
3759 }
3760
3761 #[test]
3762 fn test_validate_ncname() {
3763 assert!(xsd_validate_datatype(
3764 &XsdDatatypeKind::NCName,
3765 "myElement",
3766 &[]
3767 ));
3768 assert!(xsd_validate_datatype(&XsdDatatypeKind::NCName, "_foo", &[]));
3769 assert!(!xsd_validate_datatype(
3770 &XsdDatatypeKind::NCName,
3771 "123abc",
3772 &[]
3773 ));
3774 assert!(!xsd_validate_datatype(&XsdDatatypeKind::NCName, "", &[]));
3775 }
3776
3777 #[test]
3778 fn test_validate_qname() {
3779 assert!(xsd_validate_datatype(
3780 &XsdDatatypeKind::QName,
3781 "ns:local",
3782 &[]
3783 ));
3784 assert!(xsd_validate_datatype(&XsdDatatypeKind::QName, "local", &[]));
3785 assert!(!xsd_validate_datatype(&XsdDatatypeKind::QName, "", &[]));
3786 }
3787
3788 #[test]
3789 fn test_validate_token() {
3790 assert!(xsd_validate_datatype(&XsdDatatypeKind::Token, "hello", &[]));
3791 assert!(!xsd_validate_datatype(
3792 &XsdDatatypeKind::Token,
3793 " hello",
3794 &[]
3795 ));
3796 assert!(!xsd_validate_datatype(
3797 &XsdDatatypeKind::Token,
3798 "hello ",
3799 &[]
3800 ));
3801 assert!(!xsd_validate_datatype(
3802 &XsdDatatypeKind::Token,
3803 "hello world",
3804 &[]
3805 ));
3806 assert!(!xsd_validate_datatype(
3807 &XsdDatatypeKind::Token,
3808 "hello\tworld",
3809 &[]
3810 ));
3811 }
3812
3813 #[test]
3814 fn test_validate_language() {
3815 assert!(xsd_validate_datatype(&XsdDatatypeKind::Language, "en", &[]));
3816 assert!(xsd_validate_datatype(
3817 &XsdDatatypeKind::Language,
3818 "en-US",
3819 &[]
3820 ));
3821 assert!(xsd_validate_datatype(
3822 &XsdDatatypeKind::Language,
3823 "zh-CN",
3824 &[]
3825 ));
3826 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Language, "", &[]));
3827 assert!(!xsd_validate_datatype(
3828 &XsdDatatypeKind::Language,
3829 "123",
3830 &[]
3831 ));
3832 }
3833
3834 #[test]
3835 fn test_validate_name() {
3836 assert!(xsd_validate_datatype(
3837 &XsdDatatypeKind::Name,
3838 "myElement",
3839 &[]
3840 ));
3841 assert!(xsd_validate_datatype(
3842 &XsdDatatypeKind::Name,
3843 "ns:local",
3844 &[]
3845 ));
3846 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Name, "", &[]));
3847 }
3848
3849 #[test]
3850 fn test_validate_nmtoken() {
3851 assert!(xsd_validate_datatype(
3852 &XsdDatatypeKind::Nmtoken,
3853 "token123",
3854 &[]
3855 ));
3856 assert!(xsd_validate_datatype(
3857 &XsdDatatypeKind::Nmtoken,
3858 "123token",
3859 &[]
3860 ));
3861 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Nmtoken, "", &[]));
3862 }
3863
3864 #[test]
3865 fn test_validate_duration() {
3866 assert!(xsd_validate_datatype(
3867 &XsdDatatypeKind::Duration,
3868 "P1Y2M3DT4H5M6S",
3869 &[]
3870 ));
3871 assert!(xsd_validate_datatype(
3872 &XsdDatatypeKind::Duration,
3873 "P1Y",
3874 &[]
3875 ));
3876 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Duration, "", &[]));
3877 }
3878
3879 #[test]
3880 fn test_validate_g_year() {
3881 assert!(xsd_validate_datatype(&XsdDatatypeKind::GYear, "2023", &[]));
3882 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GYear, "", &[]));
3883 }
3884
3885 #[test]
3886 fn test_validate_g_month() {
3887 assert!(xsd_validate_datatype(&XsdDatatypeKind::GMonth, "--05", &[]));
3888 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GMonth, "", &[]));
3889 }
3890
3891 #[test]
3892 fn test_validate_g_day() {
3893 assert!(xsd_validate_datatype(&XsdDatatypeKind::GDay, "---15", &[]));
3894 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GDay, "", &[]));
3895 }
3896
3897 #[test]
3900 fn test_facet_min_length() {
3901 let facets = vec![(XsdDatatypeKind::FacetMinLength, "3".to_string())];
3902 assert!(xsd_validate_datatype(
3903 &XsdDatatypeKind::String,
3904 "hello",
3905 &facets
3906 ));
3907 assert!(xsd_validate_datatype(
3908 &XsdDatatypeKind::String,
3909 "abc",
3910 &facets
3911 ));
3912 assert!(!xsd_validate_datatype(
3913 &XsdDatatypeKind::String,
3914 "ab",
3915 &facets
3916 ));
3917 }
3918
3919 #[test]
3920 fn test_facet_max_length() {
3921 let facets = vec![(XsdDatatypeKind::FacetMaxLength, "3".to_string())];
3922 assert!(xsd_validate_datatype(
3923 &XsdDatatypeKind::String,
3924 "ab",
3925 &facets
3926 ));
3927 assert!(xsd_validate_datatype(
3928 &XsdDatatypeKind::String,
3929 "abc",
3930 &facets
3931 ));
3932 assert!(!xsd_validate_datatype(
3933 &XsdDatatypeKind::String,
3934 "abcd",
3935 &facets
3936 ));
3937 }
3938
3939 #[test]
3940 fn test_facet_length() {
3941 let facets = vec![(XsdDatatypeKind::FacetLength, "3".to_string())];
3942 assert!(xsd_validate_datatype(
3943 &XsdDatatypeKind::String,
3944 "abc",
3945 &facets
3946 ));
3947 assert!(!xsd_validate_datatype(
3948 &XsdDatatypeKind::String,
3949 "ab",
3950 &facets
3951 ));
3952 assert!(!xsd_validate_datatype(
3953 &XsdDatatypeKind::String,
3954 "abcd",
3955 &facets
3956 ));
3957 }
3958
3959 #[test]
3960 fn test_facet_min_inclusive() {
3961 let facets = vec![(XsdDatatypeKind::FacetMinInclusive, "5".to_string())];
3962 assert!(xsd_validate_datatype(
3963 &XsdDatatypeKind::Integer,
3964 "5",
3965 &facets
3966 ));
3967 assert!(xsd_validate_datatype(
3968 &XsdDatatypeKind::Integer,
3969 "10",
3970 &facets
3971 ));
3972 assert!(!xsd_validate_datatype(
3973 &XsdDatatypeKind::Integer,
3974 "3",
3975 &facets
3976 ));
3977 }
3978
3979 #[test]
3980 fn test_facet_max_inclusive() {
3981 let facets = vec![(XsdDatatypeKind::FacetMaxInclusive, "10".to_string())];
3982 assert!(xsd_validate_datatype(
3983 &XsdDatatypeKind::Integer,
3984 "10",
3985 &facets
3986 ));
3987 assert!(xsd_validate_datatype(
3988 &XsdDatatypeKind::Integer,
3989 "5",
3990 &facets
3991 ));
3992 assert!(!xsd_validate_datatype(
3993 &XsdDatatypeKind::Integer,
3994 "15",
3995 &facets
3996 ));
3997 }
3998
3999 #[test]
4000 fn test_facet_pattern_digits() {
4001 let facets = vec![(XsdDatatypeKind::FacetPattern, r"\d+".to_string())];
4002 assert!(xsd_validate_datatype(
4003 &XsdDatatypeKind::String,
4004 "123",
4005 &facets
4006 ));
4007 assert!(!xsd_validate_datatype(
4008 &XsdDatatypeKind::String,
4009 "abc",
4010 &facets
4011 ));
4012 }
4013
4014 #[test]
4015 fn test_facet_pattern_alpha() {
4016 let facets = vec![(XsdDatatypeKind::FacetPattern, r"[a-zA-Z]+".to_string())];
4017 assert!(xsd_validate_datatype(
4018 &XsdDatatypeKind::String,
4019 "hello",
4020 &facets
4021 ));
4022 assert!(!xsd_validate_datatype(
4023 &XsdDatatypeKind::String,
4024 "123",
4025 &facets
4026 ));
4027 }
4028
4029 #[test]
4032 fn test_parse_empty_schema() {
4033 let schema_xml = r#"<?xml version="1.0"?>
4034 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4035 </xs:schema>"#;
4036
4037 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4038 assert!(schema.components.is_empty());
4039 }
4040
4041 #[test]
4042 fn test_parse_schema_with_target_namespace() {
4043 let schema_xml = r#"<?xml version="1.0"?>
4044 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
4045 targetNamespace="http://example.com/ns">
4046 </xs:schema>"#;
4047
4048 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4049 assert_eq!(
4050 schema.target_namespace,
4051 Some("http://example.com/ns".to_string())
4052 );
4053 }
4054
4055 #[test]
4056 fn test_parse_simple_element() {
4057 let schema_xml = r#"<?xml version="1.0"?>
4058 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4059 <xs:element name="name" type="xs:string"/>
4060 </xs:schema>"#;
4061
4062 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4063 assert_eq!(schema.components.len(), 1);
4064 assert_eq!(
4065 schema.components[0].component_type,
4066 XsdComponentType::Element
4067 );
4068 assert_eq!(schema.components[0].name, Some("name".to_string()));
4069 assert_eq!(schema.components[0].datatype, Some(XsdDatatypeKind::String));
4070 }
4071
4072 #[test]
4073 fn test_parse_integer_element() {
4074 let schema_xml = r#"<?xml version="1.0"?>
4075 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4076 <xs:element name="age" type="xs:integer"/>
4077 </xs:schema>"#;
4078
4079 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4080 assert_eq!(schema.components.len(), 1);
4081 assert_eq!(schema.components[0].name, Some("age".to_string()));
4082 assert_eq!(
4083 schema.components[0].datatype,
4084 Some(XsdDatatypeKind::Integer)
4085 );
4086 }
4087
4088 #[test]
4089 fn test_parse_element_with_attributes() {
4090 let schema_xml = r#"<?xml version="1.0"?>
4091 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4092 <xs:element name="product">
4093 <xs:complexType>
4094 <xs:sequence>
4095 <xs:element name="name" type="xs:string"/>
4096 <xs:element name="price" type="xs:decimal"/>
4097 </xs:sequence>
4098 <xs:attribute name="id" type="xs:integer" use="required"/>
4099 </xs:complexType>
4100 </xs:element>
4101 </xs:schema>"#;
4102
4103 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4104 assert_eq!(schema.components.len(), 1);
4105 assert_eq!(schema.components[0].name, Some("product".to_string()));
4106
4107 let ct = &schema.components[0].children;
4109 let complex_type = ct
4110 .iter()
4111 .find(|c| c.component_type == XsdComponentType::ComplexType);
4112 assert!(complex_type.is_some());
4113 if let Some(ctc) = complex_type {
4114 assert_eq!(ctc.attributes.len(), 1);
4115 assert_eq!(ctc.attributes[0].name, Some("id".to_string()));
4116 assert_eq!(ctc.attributes[0].datatype, Some(XsdDatatypeKind::Integer));
4117 }
4118 }
4119
4120 #[test]
4121 fn test_parse_complex_type_with_sequence() {
4122 let schema_xml = r#"<?xml version="1.0"?>
4123 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4124 <xs:complexType name="AddressType">
4125 <xs:sequence>
4126 <xs:element name="street" type="xs:string"/>
4127 <xs:element name="city" type="xs:string"/>
4128 <xs:element name="zip" type="xs:string"/>
4129 </xs:sequence>
4130 </xs:complexType>
4131 </xs:schema>"#;
4132
4133 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4134 assert_eq!(schema.components.len(), 1);
4135 assert_eq!(
4136 schema.components[0].component_type,
4137 XsdComponentType::ComplexType
4138 );
4139 assert_eq!(schema.components[0].name, Some("AddressType".to_string()));
4140 }
4141
4142 #[test]
4143 fn test_parse_restriction() {
4144 let schema_xml = r#"<?xml version="1.0"?>
4145 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4146 <xs:simpleType name="AgeType">
4147 <xs:restriction base="xs:integer">
4148 <xs:minInclusive value="0"/>
4149 <xs:maxInclusive value="150"/>
4150 </xs:restriction>
4151 </xs:simpleType>
4152 </xs:schema>"#;
4153
4154 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4155 assert_eq!(schema.components.len(), 1);
4156 assert_eq!(
4157 schema.components[0].component_type,
4158 XsdComponentType::SimpleType
4159 );
4160
4161 let st = &schema.components[0];
4163 assert_eq!(st.datatype, Some(XsdDatatypeKind::Integer));
4164 assert!(!st.facets.is_empty());
4165 }
4166
4167 #[test]
4168 fn test_parse_enumeration() {
4169 let schema_xml = r#"<?xml version="1.0"?>
4170 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4171 <xs:simpleType name="ColorType">
4172 <xs:restriction base="xs:string">
4173 <xs:enumeration value="red"/>
4174 <xs:enumeration value="green"/>
4175 <xs:enumeration value="blue"/>
4176 </xs:restriction>
4177 </xs:simpleType>
4178 </xs:schema>"#;
4179
4180 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4181 assert_eq!(schema.components.len(), 1);
4182 assert_eq!(schema.components[0].name, Some("ColorType".to_string()));
4183 }
4184
4185 #[test]
4186 fn test_parse_min_max_occurs() {
4187 let schema_xml = r#"<?xml version="1.0"?>
4188 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4189 <xs:element name="items">
4190 <xs:complexType>
4191 <xs:sequence>
4192 <xs:element name="item" type="xs:string"
4193 minOccurs="0" maxOccurs="unbounded"/>
4194 </xs:sequence>
4195 </xs:complexType>
4196 </xs:element>
4197 </xs:schema>"#;
4198
4199 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4200 assert_eq!(schema.components.len(), 1);
4201
4202 let elem = &schema.components[0];
4204 let ct = elem
4205 .children
4206 .iter()
4207 .find(|c| c.component_type == XsdComponentType::ComplexType);
4208 assert!(ct.is_some());
4209 if let Some(ctc) = ct {
4210 let seq = ctc
4211 .children
4212 .iter()
4213 .find(|c| c.component_type == XsdComponentType::Sequence);
4214 assert!(seq.is_some());
4215 if let Some(seqc) = seq {
4216 assert!(!seqc.children.is_empty());
4217 let item = &seqc.children[0];
4218 assert_eq!(item.min_occurs, 0);
4219 assert_eq!(item.max_occurs, -1);
4220 }
4221 }
4222 }
4223
4224 #[test]
4225 fn test_parse_attribute_default() {
4226 let schema_xml = r#"<?xml version="1.0"?>
4227 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4228 <xs:element name="book">
4229 <xs:complexType>
4230 <xs:sequence>
4231 <xs:element name="title" type="xs:string"/>
4232 </xs:sequence>
4233 <xs:attribute name="lang" type="xs:string" default="en"/>
4234 <xs:attribute name="id" type="xs:integer" use="required"/>
4235 </xs:complexType>
4236 </xs:element>
4237 </xs:schema>"#;
4238
4239 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4240 let elem = &schema.components[0];
4241 let ct = elem
4242 .children
4243 .iter()
4244 .find(|c| c.component_type == XsdComponentType::ComplexType);
4245 assert!(ct.is_some());
4246 if let Some(ctc) = ct {
4247 let lang_attr = ctc
4248 .attributes
4249 .iter()
4250 .find(|a| a.name.as_deref() == Some("lang"));
4251 assert!(lang_attr.is_some());
4252 if let Some(la) = lang_attr {
4253 assert_eq!(la.min_occurs, 0); }
4255
4256 let id_attr = ctc
4257 .attributes
4258 .iter()
4259 .find(|a| a.name.as_deref() == Some("id"));
4260 assert!(id_attr.is_some());
4261 }
4262 }
4263
4264 #[test]
4265 fn test_parse_element_with_ref() {
4266 let schema_xml = r#"<?xml version="1.0"?>
4267 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4268 <xs:element name="root">
4269 <xs:complexType>
4270 <xs:sequence>
4271 <xs:element ref="child" minOccurs="0"/>
4272 </xs:sequence>
4273 </xs:complexType>
4274 </xs:element>
4275 <xs:element name="child" type="xs:string"/>
4276 </xs:schema>"#;
4277
4278 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4279 assert_eq!(schema.components.len(), 2);
4280 let root = &schema.components[0];
4282 let ct = root
4283 .children
4284 .iter()
4285 .find(|c| c.component_type == XsdComponentType::ComplexType);
4286 assert!(ct.is_some());
4287 if let Some(ctc) = ct {
4288 let seq = ctc
4289 .children
4290 .iter()
4291 .find(|c| c.component_type == XsdComponentType::Sequence);
4292 assert!(seq.is_some());
4293 if let Some(seqc) = seq {
4294 assert!(!seqc.children.is_empty());
4295 let ref_elem = &seqc.children[0];
4296 assert_eq!(ref_elem.ref_name, Some("child".to_string()));
4297 }
4298 }
4299 }
4300
4301 #[test]
4304 fn test_validate_simple_element() {
4305 let schema_xml = r#"<?xml version="1.0"?>
4306 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4307 <xs:element name="name" type="xs:string"/>
4308 </xs:schema>"#;
4309
4310 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4311
4312 let doc = r#"<?xml version="1.0"?>
4313 <name>John Doe</name>"#;
4314
4315 assert!(xsd_validate(&schema, doc).is_ok());
4316 }
4317
4318 #[test]
4319 fn test_validate_integer_element() {
4320 let schema_xml = r#"<?xml version="1.0"?>
4321 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4322 <xs:element name="age" type="xs:integer"/>
4323 </xs:schema>"#;
4324
4325 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4326
4327 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
4328 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>not-a-number</age>"#).is_err());
4329 }
4330
4331 #[test]
4332 fn test_validate_complex_element() {
4333 let schema_xml = r#"<?xml version="1.0"?>
4334 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4335 <xs:element name="product">
4336 <xs:complexType>
4337 <xs:sequence>
4338 <xs:element name="name" type="xs:string"/>
4339 <xs:element name="price" type="xs:decimal"/>
4340 </xs:sequence>
4341 <xs:attribute name="id" type="xs:integer" use="required"/>
4342 </xs:complexType>
4343 </xs:element>
4344 </xs:schema>"#;
4345
4346 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4347
4348 let valid_doc = r#"<?xml version="1.0"?>
4349 <product id="123">
4350 <name>Widget</name>
4351 <price>9.99</price>
4352 </product>"#;
4353
4354 assert!(xsd_validate(&schema, valid_doc).is_ok());
4355 }
4356
4357 #[test]
4358 fn test_validate_missing_required_attribute() {
4359 let schema_xml = r#"<?xml version="1.0"?>
4360 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4361 <xs:element name="product">
4362 <xs:complexType>
4363 <xs:sequence>
4364 <xs:element name="name" type="xs:string"/>
4365 </xs:sequence>
4366 <xs:attribute name="id" type="xs:integer" use="required"/>
4367 </xs:complexType>
4368 </xs:element>
4369 </xs:schema>"#;
4370
4371 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4372
4373 let invalid_doc = r#"<?xml version="1.0"?>
4374 <product>
4375 <name>Widget</name>
4376 </product>"#;
4377
4378 assert!(xsd_validate(&schema, invalid_doc).is_err());
4379 }
4380
4381 #[test]
4382 fn test_validate_enumeration_facet() {
4383 let schema_xml = r#"<?xml version="1.0"?>
4384 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4385 <xs:element name="color">
4386 <xs:simpleType>
4387 <xs:restriction base="xs:string">
4388 <xs:enumeration value="red"/>
4389 <xs:enumeration value="green"/>
4390 <xs:enumeration value="blue"/>
4391 </xs:restriction>
4392 </xs:simpleType>
4393 </xs:element>
4394 </xs:schema>"#;
4395
4396 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4397
4398 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><color>red</color>"#).is_ok());
4401 }
4402
4403 #[test]
4404 fn test_validate_boolean_element() {
4405 let schema_xml = r#"<?xml version="1.0"?>
4406 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4407 <xs:element name="active" type="xs:boolean"/>
4408 </xs:schema>"#;
4409
4410 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4411
4412 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>true</active>"#).is_ok());
4413 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>false</active>"#).is_ok());
4414 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>1</active>"#).is_ok());
4415 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>yes</active>"#).is_err());
4416 }
4417
4418 #[test]
4419 fn test_validate_element_with_range_constraint() {
4420 let schema_xml = r#"<?xml version="1.0"?>
4421 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4422 <xs:element name="age">
4423 <xs:simpleType>
4424 <xs:restriction base="xs:integer">
4425 <xs:minInclusive value="0"/>
4426 <xs:maxInclusive value="150"/>
4427 </xs:restriction>
4428 </xs:simpleType>
4429 </xs:element>
4430 </xs:schema>"#;
4431
4432 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4433
4434 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
4435 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>0</age>"#).is_ok());
4436 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>150</age>"#).is_ok());
4437 }
4439
4440 #[test]
4441 fn test_validate_optional_element() {
4442 let schema_xml = r#"<?xml version="1.0"?>
4443 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4444 <xs:element name="person">
4445 <xs:complexType>
4446 <xs:sequence>
4447 <xs:element name="name" type="xs:string"/>
4448 <xs:element name="nickname" type="xs:string" minOccurs="0"/>
4449 </xs:sequence>
4450 </xs:complexType>
4451 </xs:element>
4452 </xs:schema>"#;
4453
4454 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4455
4456 let doc_with_nick = r#"<?xml version="1.0"?>
4457 <person>
4458 <name>John</name>
4459 <nickname>Johnny</nickname>
4460 </person>"#;
4461
4462 let doc_without_nick = r#"<?xml version="1.0"?>
4463 <person>
4464 <name>John</name>
4465 </person>"#;
4466
4467 assert!(xsd_validate(&schema, doc_with_nick).is_ok());
4468 assert!(xsd_validate(&schema, doc_without_nick).is_ok());
4469 }
4470
4471 #[test]
4472 fn test_validate_unbounded_element() {
4473 let schema_xml = r#"<?xml version="1.0"?>
4474 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4475 <xs:element name="items">
4476 <xs:complexType>
4477 <xs:sequence>
4478 <xs:element name="item" type="xs:string"
4479 minOccurs="0" maxOccurs="unbounded"/>
4480 </xs:sequence>
4481 </xs:complexType>
4482 </xs:element>
4483 </xs:schema>"#;
4484
4485 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4486
4487 let doc = r#"<?xml version="1.0"?>
4488 <items>
4489 <item>one</item>
4490 <item>two</item>
4491 <item>three</item>
4492 </items>"#;
4493
4494 assert!(xsd_validate(&schema, doc).is_ok());
4495 }
4496
4497 #[test]
4498 fn test_validate_date_element() {
4499 let schema_xml = r#"<?xml version="1.0"?>
4500 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4501 <xs:element name="birthDate" type="xs:date"/>
4502 </xs:schema>"#;
4503
4504 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4505
4506 assert!(xsd_validate(
4507 &schema,
4508 r#"<?xml version="1.0"?><birthDate>1990-01-15</birthDate>"#
4509 )
4510 .is_ok());
4511 assert!(xsd_validate(
4512 &schema,
4513 r#"<?xml version="1.0"?><birthDate>not-a-date</birthDate>"#
4514 )
4515 .is_err());
4516 }
4517
4518 #[test]
4519 fn test_validate_choice() {
4520 let schema_xml = r#"<?xml version="1.0"?>
4521 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4522 <xs:element name="contact">
4523 <xs:complexType>
4524 <xs:choice>
4525 <xs:element name="email" type="xs:string"/>
4526 <xs:element name="phone" type="xs:string"/>
4527 </xs:choice>
4528 </xs:complexType>
4529 </xs:element>
4530 </xs:schema>"#;
4531
4532 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4533
4534 assert!(xsd_validate(
4535 &schema,
4536 r#"<?xml version="1.0"?><contact><email>a@b.com</email></contact>"#
4537 )
4538 .is_ok());
4539 assert!(xsd_validate(
4540 &schema,
4541 r#"<?xml version="1.0"?><contact><phone>555-1234</phone></contact>"#
4542 )
4543 .is_ok());
4544 }
4545
4546 #[test]
4547 fn test_validate_positive_integer_constraint() {
4548 let schema_xml = r#"<?xml version="1.0"?>
4549 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4550 <xs:element name="quantity" type="xs:positiveInteger"/>
4551 </xs:schema>"#;
4552
4553 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
4554
4555 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>1</quantity>"#).is_ok());
4556 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>0</quantity>"#).is_err());
4557 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>-1</quantity>"#).is_err());
4558 }
4559
4560 #[test]
4571 fn test_xml_schema_new_mem_parser_ctxt() {
4572 let schema_xml = r#"<?xml version="1.0"?>
4573 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4574 <xs:element name="name" type="xs:string"/>
4575 </xs:schema>"#;
4576
4577 let ctxt = unsafe {
4578 xmlSchemaNewMemParserCtxt(
4579 schema_xml.as_ptr() as *const c_char,
4580 schema_xml.len() as c_int,
4581 )
4582 };
4583 assert!(!ctxt.is_null());
4584
4585 let schema = unsafe { xmlSchemaParse(ctxt) };
4586 assert!(!schema.is_null());
4587
4588 unsafe {
4589 xmlSchemaFree(schema);
4590 }
4591 }
4592
4593 #[test]
4603 fn test_xml_schema_validate_doc() {
4604 let schema_xml = r#"<?xml version="1.0"?>
4605 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4606 <xs:element name="name" type="xs:string"/>
4607 </xs:schema>"#;
4608
4609 let doc_xml = r#"<?xml version="1.0"?>
4610 <name>John Doe</name>"#;
4611
4612 let ctxt = unsafe {
4613 xmlSchemaNewMemParserCtxt(
4614 schema_xml.as_ptr() as *const c_char,
4615 schema_xml.len() as c_int,
4616 )
4617 };
4618 let schema = unsafe { xmlSchemaParse(ctxt) };
4619 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
4620
4621 let doc = unsafe {
4622 crate::abi::exports_xml2::xmlReadMemory(
4623 doc_xml.as_ptr() as *const c_char,
4624 doc_xml.len() as c_int,
4625 c"test.xml".as_ptr() as *const c_char,
4626 ptr::null(),
4627 0,
4628 )
4629 };
4630
4631 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
4632 assert_eq!(result, 0);
4633
4634 unsafe {
4635 xmlSchemaFreeValidCtxt(valid_ctxt);
4636 xmlSchemaFree(schema);
4637 crate::abi::exports_xml2::xmlFreeDoc(doc);
4638 }
4639 }
4640
4641 #[test]
4651 fn test_xml_schema_validate_invalid_doc() {
4652 let schema_xml = r#"<?xml version="1.0"?>
4653 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4654 <xs:element name="age" type="xs:integer"/>
4655 </xs:schema>"#;
4656
4657 let doc_xml = r#"<?xml version="1.0"?>
4658 <age>not-a-number</age>"#;
4659
4660 let ctxt = unsafe {
4661 xmlSchemaNewMemParserCtxt(
4662 schema_xml.as_ptr() as *const c_char,
4663 schema_xml.len() as c_int,
4664 )
4665 };
4666 let schema = unsafe { xmlSchemaParse(ctxt) };
4667 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
4668
4669 let doc = unsafe {
4670 crate::abi::exports_xml2::xmlReadMemory(
4671 doc_xml.as_ptr() as *const c_char,
4672 doc_xml.len() as c_int,
4673 c"test.xml".as_ptr() as *const c_char,
4674 ptr::null(),
4675 0,
4676 )
4677 };
4678
4679 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
4680 assert_ne!(result, 0); unsafe {
4683 xmlSchemaFreeValidCtxt(valid_ctxt);
4684 xmlSchemaFree(schema);
4685 crate::abi::exports_xml2::xmlFreeDoc(doc);
4686 }
4687 }
4688
4689 #[test]
4701 fn test_xml_schema_validate_root_without_global_decl() {
4702 let doc = unsafe {
4703 crate::abi::exports_xml2::xmlReadMemory(
4704 c"<root/>".as_ptr() as *const c_char,
4705 7,
4706 c"test.xml".as_ptr() as *const c_char,
4707 ptr::null(),
4708 0,
4709 )
4710 };
4711 assert!(!doc.is_null());
4712
4713 let mut schema = XsdSchema::new();
4715 schema.components.push(XsdComponent {
4716 component_type: XsdComponentType::Element,
4717 name: Some("other".to_string()),
4718 ..XsdComponent::new(XsdComponentType::Element)
4719 });
4720
4721 let mut ctxt = XsdValidCtxt::new();
4722 let valid = unsafe { xsd_validate_doc(&schema, doc, &mut ctxt) };
4723 assert!(!valid);
4724 assert_eq!(ctxt.errors.len(), 1);
4725 assert!(
4726 ctxt.errors[0]
4727 .contains("No matching global declaration available for the validation root."),
4728 "unexpected diagnostic: {:?}",
4729 ctxt.errors[0]
4730 );
4731 assert!(
4732 ctxt.errors[0].contains("'root'"),
4733 "root name missing: {:?}",
4734 ctxt.errors[0]
4735 );
4736
4737 unsafe {
4738 crate::abi::exports_xml2::xmlFreeDoc(doc);
4739 }
4740 }
4741
4742 #[test]
4755 fn test_xml_schema_validate_creates_default_attrs() {
4756 let schema_xml = r#"<?xml version="1.0"?>
4757 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4758 <xs:element name="books">
4759 <xs:complexType>
4760 <xs:sequence>
4761 <xs:element name="book" minOccurs="1" maxOccurs="unbounded">
4762 <xs:complexType>
4763 <xs:attribute name="is-hardback" type="xs:boolean" default="false"/>
4764 </xs:complexType>
4765 </xs:element>
4766 </xs:sequence>
4767 </xs:complexType>
4768 </xs:element>
4769 </xs:schema>"#;
4770 let doc_xml = r#"<?xml version="1.0"?>
4771 <books><book><title>a</title></book></books>"#;
4772
4773 let ctxt = unsafe {
4779 xmlSchemaNewMemParserCtxt(
4780 schema_xml.as_ptr() as *const c_char,
4781 schema_xml.len() as c_int,
4782 )
4783 };
4784 let schema = unsafe { xmlSchemaParse(ctxt) };
4785 assert!(!schema.is_null());
4786 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
4787 assert!(!valid_ctxt.is_null());
4788
4789 let make_doc = || unsafe {
4790 crate::abi::exports_xml2::xmlReadMemory(
4791 doc_xml.as_ptr() as *const c_char,
4792 doc_xml.len() as c_int,
4793 c"test.xml".as_ptr() as *const c_char,
4794 ptr::null(),
4795 0,
4796 )
4797 };
4798 let book_of = |doc: *mut _xmlDoc| -> *mut _xmlNode {
4799 unsafe {
4800 let books = (*doc).children;
4802 assert!(!books.is_null());
4803 let book = (*books).children;
4804 assert!(!book.is_null());
4805 book
4806 }
4807 };
4808
4809 let doc = make_doc();
4811 assert_eq!(unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) }, 0);
4812 let missing = unsafe {
4813 crate::abi::exports_xml2::xmlGetProp(
4814 book_of(doc),
4815 c"is-hardback".as_ptr() as *const crate::abi::types::xmlChar,
4816 )
4817 };
4818 assert!(
4819 missing.is_null(),
4820 "attr must NOT be created without the option"
4821 );
4822 unsafe {
4823 crate::abi::exports_xml2::xmlFreeDoc(doc);
4824 }
4825
4826 let r = unsafe {
4828 crate::abi::exports_schema::xmlSchemaSetValidOptions(
4829 valid_ctxt as *mut crate::abi::exports_schema::xmlSchemaValidCtxt,
4830 1,
4831 )
4832 };
4833 assert_eq!(r, 0);
4834 let doc = make_doc();
4835 assert_eq!(unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) }, 0);
4836 let got = unsafe {
4837 crate::abi::exports_xml2::xmlGetProp(
4838 book_of(doc),
4839 c"is-hardback".as_ptr() as *const crate::abi::types::xmlChar,
4840 )
4841 };
4842 assert!(!got.is_null(), "default attribute must be created");
4843 let val = unsafe { crate::xml::string::xmlstr_to_string(got) };
4844 assert_eq!(val, "false");
4845
4846 unsafe {
4847 crate::abi::exports_xml2::xmlFreeDoc(doc);
4848 xmlSchemaFreeValidCtxt(valid_ctxt);
4849 xmlSchemaFree(schema);
4850 xmlSchemaFreeParserCtxt(ctxt);
4851 }
4852 }
4853
4854 #[test]
4862 fn test_xml_schema_new_valid_ctxt_null() {
4863 let ctxt = unsafe { xmlSchemaNewValidCtxt(ptr::null_mut()) };
4864 assert!(!ctxt.is_null());
4865 unsafe { xmlSchemaFreeValidCtxt(ctxt) };
4866 }
4867
4868 #[test]
4876 fn test_xml_schema_free_null() {
4877 unsafe {
4878 xmlSchemaFree(ptr::null_mut());
4879 xmlSchemaFreeParserCtxt(ptr::null_mut());
4880 xmlSchemaFreeValidCtxt(ptr::null_mut());
4881 }
4882 }
4883
4884 #[test]
4892 fn test_xml_schema_new_parser_ctxt_null() {
4893 let ctxt = unsafe { xmlSchemaNewParserCtxt(ptr::null()) };
4894 assert!(!ctxt.is_null());
4895 unsafe {
4897 crate::abi::allocator::xmlFreeImpl(ctxt);
4898 }
4899 }
4900
4901 #[test]
4902 fn test_datatype_parse_kind() {
4903 assert_eq!(
4904 parse_datatype_kind("xs:string"),
4905 Some(XsdDatatypeKind::String)
4906 );
4907 assert_eq!(parse_datatype_kind("string"), Some(XsdDatatypeKind::String));
4908 assert_eq!(
4909 parse_datatype_kind("xs:integer"),
4910 Some(XsdDatatypeKind::Integer)
4911 );
4912 assert_eq!(
4913 parse_datatype_kind("xs:boolean"),
4914 Some(XsdDatatypeKind::Boolean)
4915 );
4916 assert_eq!(
4917 parse_datatype_kind("xs:decimal"),
4918 Some(XsdDatatypeKind::Decimal)
4919 );
4920 assert_eq!(
4921 parse_datatype_kind("xs:float"),
4922 Some(XsdDatatypeKind::Float)
4923 );
4924 assert_eq!(
4925 parse_datatype_kind("xs:double"),
4926 Some(XsdDatatypeKind::Double)
4927 );
4928 assert_eq!(parse_datatype_kind("xs:date"), Some(XsdDatatypeKind::Date));
4929 assert_eq!(
4930 parse_datatype_kind("xs:dateTime"),
4931 Some(XsdDatatypeKind::DateTime)
4932 );
4933 assert_eq!(parse_datatype_kind("xs:time"), Some(XsdDatatypeKind::Time));
4934 assert_eq!(
4935 parse_datatype_kind("xs:hexBinary"),
4936 Some(XsdDatatypeKind::HexBinary)
4937 );
4938 assert_eq!(
4939 parse_datatype_kind("xs:base64Binary"),
4940 Some(XsdDatatypeKind::Base64Binary)
4941 );
4942 assert_eq!(
4943 parse_datatype_kind("xs:anyURI"),
4944 Some(XsdDatatypeKind::AnyURI)
4945 );
4946 assert_eq!(
4947 parse_datatype_kind("xs:QName"),
4948 Some(XsdDatatypeKind::QName)
4949 );
4950 assert_eq!(
4951 parse_datatype_kind("xs:normalizedString"),
4952 Some(XsdDatatypeKind::NormalizedString)
4953 );
4954 assert_eq!(
4955 parse_datatype_kind("xs:token"),
4956 Some(XsdDatatypeKind::Token)
4957 );
4958 assert_eq!(
4959 parse_datatype_kind("xs:language"),
4960 Some(XsdDatatypeKind::Language)
4961 );
4962 assert_eq!(parse_datatype_kind("xs:Name"), Some(XsdDatatypeKind::Name));
4963 assert_eq!(
4964 parse_datatype_kind("xs:NCName"),
4965 Some(XsdDatatypeKind::NCName)
4966 );
4967 assert_eq!(parse_datatype_kind("xs:ID"), Some(XsdDatatypeKind::Id));
4968 assert_eq!(
4969 parse_datatype_kind("xs:IDREF"),
4970 Some(XsdDatatypeKind::Idref)
4971 );
4972 assert_eq!(
4973 parse_datatype_kind("xs:integer"),
4974 Some(XsdDatatypeKind::Integer)
4975 );
4976 assert_eq!(parse_datatype_kind("xs:long"), Some(XsdDatatypeKind::Long));
4977 assert_eq!(parse_datatype_kind("xs:int"), Some(XsdDatatypeKind::Int));
4978 assert_eq!(
4979 parse_datatype_kind("xs:short"),
4980 Some(XsdDatatypeKind::Short)
4981 );
4982 assert_eq!(parse_datatype_kind("xs:byte"), Some(XsdDatatypeKind::Byte));
4983 assert_eq!(
4984 parse_datatype_kind("xs:positiveInteger"),
4985 Some(XsdDatatypeKind::PositiveInteger)
4986 );
4987 assert_eq!(
4988 parse_datatype_kind("xs:negativeInteger"),
4989 Some(XsdDatatypeKind::NegativeInteger)
4990 );
4991 assert_eq!(parse_datatype_kind("unknown"), None);
4992 }
4993}