1use core::ffi::c_void;
17use core::ptr;
18use std::os::raw::{c_char, c_int};
19
20use crate::abi::allocator;
21use crate::abi::structs::*;
22use crate::abi::types::xmlElementType::*;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum XsdComponentType {
35 Schema,
38 Element,
40 Attribute,
42 ComplexType,
44 SimpleType,
46 SimpleContent,
48 ComplexContent,
50 Sequence,
52 Choice,
54 All,
56 Restriction,
58 Extension,
60 List,
62 Union,
64 Annotation,
66 Any,
68 AnyAttribute,
70 Group,
72 AttributeGroup,
74 Notation,
76 Unique,
78 Key,
80 KeyRef,
82 Selector,
84 Field,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99pub enum XsdDatatypeKind {
100 String,
103 Boolean,
105 Decimal,
108 Float,
111 Double,
114 Duration,
117 DateTime,
119 Time,
121 Date,
123 GYearMonth,
125 GYear,
127 GMonthDay,
129 GDay,
131 GMonth,
133 HexBinary,
136 Base64Binary,
138 AnyURI,
140 QName,
142 Notation,
145 NormalizedString,
149 Token,
152 Language,
155 Nmtoken,
157 Nmtokens,
159 Name,
161 NCName,
163 Id,
165 Idref,
167 Idrefs,
169 Entity,
171 Entities,
173 Integer,
176 NonPositiveInteger,
178 NegativeInteger,
180 Long,
182 Int,
184 Short,
186 Byte,
188 NonNegativeInteger,
190 UnsignedLong,
192 UnsignedInt,
194 UnsignedShort,
196 UnsignedByte,
198 PositiveInteger,
200 FacetPattern,
203 FacetEnumeration,
206 FacetMinInclusive,
208 FacetMaxInclusive,
210 FacetMinExclusive,
212 FacetMaxExclusive,
214 FacetMinLength,
216 FacetMaxLength,
218 FacetLength,
220 FacetWhiteSpace,
223 FacetFractionDigits,
226 FacetTotalDigits,
228}
229
230#[derive(Debug, Clone)]
239pub struct XsdComponent {
240 pub component_type: XsdComponentType,
242 pub name: Option<String>,
245 pub target_namespace: Option<String>,
247 pub children: Vec<XsdComponent>,
249 pub attributes: Vec<XsdComponent>,
251 pub datatype: Option<XsdDatatypeKind>,
254 pub facets: Vec<(XsdDatatypeKind, String)>,
256 pub base: Option<String>,
259 pub min_occurs: i32,
262 pub max_occurs: i32,
264 pub ref_name: Option<String>,
267 pub substitution_group: Option<String>,
269 pub is_abstract: bool,
271 pub is_final: bool,
273 pub block: Vec<String>,
275 pub mixed: bool,
277 pub form: Option<String>,
280}
281
282impl XsdComponent {
283 pub const fn new(component_type: XsdComponentType) -> Self {
287 Self {
288 component_type,
289 name: None,
290 target_namespace: None,
291 children: Vec::new(),
292 attributes: Vec::new(),
293 datatype: None,
294 facets: Vec::new(),
295 base: None,
296 min_occurs: 1,
297 max_occurs: 1,
298 ref_name: None,
299 substitution_group: None,
300 is_abstract: false,
301 is_final: false,
302 block: Vec::new(),
303 mixed: false,
304 form: None,
305 }
306 }
307}
308
309#[derive(Debug, Clone)]
317pub struct XsdSchema {
318 pub components: Vec<XsdComponent>,
320 pub target_namespace: Option<String>,
322 pub element_form_default: Option<String>,
324 pub attribute_form_default: Option<String>,
326 pub errors: Vec<String>,
328}
329
330impl XsdSchema {
331 pub const fn new() -> Self {
333 Self {
334 components: Vec::new(),
335 target_namespace: None,
336 element_form_default: None,
337 attribute_form_default: None,
338 errors: Vec::new(),
339 }
340 }
341}
342
343impl Default for XsdSchema {
344 fn default() -> Self {
345 Self::new()
346 }
347}
348
349#[derive(Debug)]
358pub struct XsdValidCtxt {
359 pub schema: Option<XsdSchema>,
361 pub errors: Vec<String>,
363 pub nb_errors: i32,
365}
366
367impl XsdValidCtxt {
368 pub const fn new() -> Self {
370 Self {
371 schema: None,
372 errors: Vec::new(),
373 nb_errors: 0,
374 }
375 }
376}
377
378impl Default for XsdValidCtxt {
379 fn default() -> Self {
380 Self::new()
381 }
382}
383
384unsafe fn get_node_text(node: *mut _xmlNode) -> String {
394 if node.is_null() {
395 return String::new();
396 }
397 let mut result = String::new();
398 unsafe {
399 let mut child = (*node).children;
400 while !child.is_null() {
401 if ((*child).type_ == XML_TEXT_NODE as c_int
402 || (*child).type_ == XML_CDATA_SECTION_NODE as c_int)
403 && !(*child).content.is_null()
404 {
405 let content = (*child).content;
406 let mut len = 0;
407 while *content.add(len) != 0 {
408 len += 1;
409 }
410 let slice = std::slice::from_raw_parts(content, len);
411 result.push_str(&String::from_utf8_lossy(slice));
412 }
413 child = (*child).next;
414 }
415 }
416 result
417}
418
419unsafe fn get_attr(node: *mut _xmlNode, name: &str) -> Option<String> {
425 if node.is_null() {
426 return None;
427 }
428 unsafe {
429 let mut prop = (*node).properties;
430 while !prop.is_null() {
431 let prop_name = (*prop).name;
432 if !prop_name.is_null() {
433 let mut len = 0;
434 while *prop_name.add(len) != 0 {
435 len += 1;
436 }
437 let slice = std::slice::from_raw_parts(prop_name, len);
438 if let Ok(s) = std::str::from_utf8(slice) {
439 if s == name {
440 return Some(get_node_text(prop as *mut _xmlNode));
441 }
442 }
443 }
444 prop = (*prop).next;
445 }
446 }
447 None
448}
449
450unsafe fn get_attr_bool(node: *mut _xmlNode, name: &str) -> bool {
456 unsafe {
457 match get_attr(node, name) {
458 Some(v) => v == "true" || v == "1",
459 None => false,
460 }
461 }
462}
463
464#[allow(dead_code)]
470unsafe fn get_attr_int(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
471 unsafe {
472 match get_attr(node, name) {
473 Some(v) => v.parse::<i32>().unwrap_or(default),
474 None => default,
475 }
476 }
477}
478
479unsafe fn get_attr_occurs(node: *mut _xmlNode, name: &str, default: i32) -> i32 {
485 unsafe {
486 match get_attr(node, name) {
487 Some(v) => {
488 if v == "unbounded" {
489 -1
490 } else {
491 v.parse::<i32>().unwrap_or(default)
492 }
493 }
494 None => default,
495 }
496 }
497}
498
499unsafe fn node_is(node: *mut _xmlNode, local_name: &str) -> bool {
505 if node.is_null() {
506 return false;
507 }
508 unsafe {
509 let name = (*node).name;
510 if name.is_null() {
511 return false;
512 }
513 let mut len = 0;
514 while *name.add(len) != 0 {
515 len += 1;
516 }
517 let slice = std::slice::from_raw_parts(name, len);
518 if let Ok(s) = std::str::from_utf8(slice) {
519 let local = if let Some(pos) = s.find(':') {
521 &s[pos + 1..]
522 } else {
523 s
524 };
525 return local == local_name;
526 }
527 }
528 false
529}
530
531fn parse_datatype_kind(name: &str) -> Option<XsdDatatypeKind> {
533 let local = if let Some(pos) = name.find(':') {
535 &name[pos + 1..]
536 } else {
537 name
538 };
539
540 match local {
541 "string" => Some(XsdDatatypeKind::String),
542 "boolean" => Some(XsdDatatypeKind::Boolean),
543 "decimal" => Some(XsdDatatypeKind::Decimal),
544 "float" => Some(XsdDatatypeKind::Float),
545 "double" => Some(XsdDatatypeKind::Double),
546 "duration" => Some(XsdDatatypeKind::Duration),
547 "dateTime" => Some(XsdDatatypeKind::DateTime),
548 "time" => Some(XsdDatatypeKind::Time),
549 "date" => Some(XsdDatatypeKind::Date),
550 "gYearMonth" => Some(XsdDatatypeKind::GYearMonth),
551 "gYear" => Some(XsdDatatypeKind::GYear),
552 "gMonthDay" => Some(XsdDatatypeKind::GMonthDay),
553 "gDay" => Some(XsdDatatypeKind::GDay),
554 "gMonth" => Some(XsdDatatypeKind::GMonth),
555 "hexBinary" => Some(XsdDatatypeKind::HexBinary),
556 "base64Binary" => Some(XsdDatatypeKind::Base64Binary),
557 "anyURI" => Some(XsdDatatypeKind::AnyURI),
558 "QName" => Some(XsdDatatypeKind::QName),
559 "NOTATION" => Some(XsdDatatypeKind::Notation),
560 "normalizedString" => Some(XsdDatatypeKind::NormalizedString),
561 "token" => Some(XsdDatatypeKind::Token),
562 "language" => Some(XsdDatatypeKind::Language),
563 "NMTOKEN" => Some(XsdDatatypeKind::Nmtoken),
564 "NMTOKENS" => Some(XsdDatatypeKind::Nmtokens),
565 "Name" => Some(XsdDatatypeKind::Name),
566 "NCName" => Some(XsdDatatypeKind::NCName),
567 "ID" => Some(XsdDatatypeKind::Id),
568 "IDREF" => Some(XsdDatatypeKind::Idref),
569 "IDREFS" => Some(XsdDatatypeKind::Idrefs),
570 "ENTITY" => Some(XsdDatatypeKind::Entity),
571 "ENTITIES" => Some(XsdDatatypeKind::Entities),
572 "integer" => Some(XsdDatatypeKind::Integer),
573 "nonPositiveInteger" => Some(XsdDatatypeKind::NonPositiveInteger),
574 "negativeInteger" => Some(XsdDatatypeKind::NegativeInteger),
575 "long" => Some(XsdDatatypeKind::Long),
576 "int" => Some(XsdDatatypeKind::Int),
577 "short" => Some(XsdDatatypeKind::Short),
578 "byte" => Some(XsdDatatypeKind::Byte),
579 "nonNegativeInteger" => Some(XsdDatatypeKind::NonNegativeInteger),
580 "unsignedLong" => Some(XsdDatatypeKind::UnsignedLong),
581 "unsignedInt" => Some(XsdDatatypeKind::UnsignedInt),
582 "unsignedShort" => Some(XsdDatatypeKind::UnsignedShort),
583 "unsignedByte" => Some(XsdDatatypeKind::UnsignedByte),
584 "positiveInteger" => Some(XsdDatatypeKind::PositiveInteger),
585 _ => None,
586 }
587}
588
589fn parse_facet_kind(name: &str) -> Option<XsdDatatypeKind> {
591 match name {
592 "pattern" => Some(XsdDatatypeKind::FacetPattern),
593 "enumeration" => Some(XsdDatatypeKind::FacetEnumeration),
594 "minInclusive" => Some(XsdDatatypeKind::FacetMinInclusive),
595 "maxInclusive" => Some(XsdDatatypeKind::FacetMaxInclusive),
596 "minExclusive" => Some(XsdDatatypeKind::FacetMinExclusive),
597 "maxExclusive" => Some(XsdDatatypeKind::FacetMaxExclusive),
598 "minLength" => Some(XsdDatatypeKind::FacetMinLength),
599 "maxLength" => Some(XsdDatatypeKind::FacetMaxLength),
600 "length" => Some(XsdDatatypeKind::FacetLength),
601 "whiteSpace" => Some(XsdDatatypeKind::FacetWhiteSpace),
602 "fractionDigits" => Some(XsdDatatypeKind::FacetFractionDigits),
603 "totalDigits" => Some(XsdDatatypeKind::FacetTotalDigits),
604 _ => None,
605 }
606}
607
608pub fn xsd_parse(xml_doc: &str) -> Result<XsdSchema, String> {
620 let doc_ptr = unsafe {
622 crate::abi::exports_xml2::xmlReadMemory(
623 xml_doc.as_ptr() as *const c_char,
624 xml_doc.len() as c_int,
625 c"schema.xsd".as_ptr() as *const c_char,
626 ptr::null(),
627 0,
628 )
629 };
630
631 if doc_ptr.is_null() {
632 return Err("Failed to parse schema XML document".to_string());
633 }
634
635 let result = unsafe { xsd_parse_schema_doc(doc_ptr) };
636 unsafe {
637 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
638 }
639 result
640}
641
642unsafe fn xsd_parse_schema_doc(doc: *mut _xmlDoc) -> Result<XsdSchema, String> {
648 unsafe {
649 let root = (*doc).children;
650 if root.is_null() {
651 return Err("Schema document has no root element".to_string());
652 }
653
654 let mut schema_node = root;
656 while !schema_node.is_null() && !node_is(schema_node, "schema") {
657 schema_node = (*schema_node).next;
658 }
659
660 if schema_node.is_null() {
661 return Err("Schema document root is not <schema>".to_string());
662 }
663
664 Ok(xsd_parse_schema_node(schema_node))
665 }
666}
667
668unsafe fn xsd_parse_schema_node(node: *mut _xmlNode) -> XsdSchema {
674 unsafe {
675 let mut schema = XsdSchema::new();
676 schema.target_namespace = get_attr(node, "targetNamespace");
677 schema.element_form_default = get_attr(node, "elementFormDefault");
678 schema.attribute_form_default = get_attr(node, "attributeFormDefault");
679
680 let mut child = (*node).children;
682 while !child.is_null() {
683 if (*child).type_ == XML_ELEMENT_NODE as c_int {
684 let comp = xsd_parse_component(child, &schema);
685 if comp.component_type != XsdComponentType::Annotation {
686 schema.components.push(comp);
687 }
688 }
689 child = (*child).next;
690 }
691
692 schema
693 }
694}
695
696unsafe fn xsd_parse_component(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
702 unsafe {
703 let name_str = if !(*node).name.is_null() {
705 let mut len = 0;
706 while *(*node).name.add(len) != 0 {
707 len += 1;
708 }
709 let slice = std::slice::from_raw_parts((*node).name, len);
710 if let Ok(s) = std::str::from_utf8(slice) {
711 if let Some(pos) = s.find(':') {
712 s[pos + 1..].to_string()
713 } else {
714 s.to_string()
715 }
716 } else {
717 String::new()
718 }
719 } else {
720 String::new()
721 };
722
723 match name_str.as_str() {
724 "element" => xsd_parse_element(node, schema),
725 "attribute" => xsd_parse_attribute_node(node, schema),
726 "complexType" => xsd_parse_complex_type(node, schema),
727 "simpleType" => xsd_parse_simple_type(node, schema),
728 "sequence" => xsd_parse_model_group(node, XsdComponentType::Sequence, schema),
729 "choice" => xsd_parse_model_group(node, XsdComponentType::Choice, schema),
730 "all" => xsd_parse_model_group(node, XsdComponentType::All, schema),
731 "restriction" => xsd_parse_restriction(node, schema),
732 "extension" => xsd_parse_extension(node, schema),
733 "list" => xsd_parse_list(node, schema),
734 "union" => xsd_parse_union(node, schema),
735 "annotation" => xsd_parse_annotation(node),
736 "any" => xsd_parse_any(node, schema),
737 "anyAttribute" => XsdComponent::new(XsdComponentType::AnyAttribute),
738 "group" => xsd_parse_group(node, schema),
739 "attributeGroup" => xsd_parse_attribute_group(node, schema),
740 "unique" => xsd_parse_identity_constraint(node, XsdComponentType::Unique, schema),
741 "key" => xsd_parse_identity_constraint(node, XsdComponentType::Key, schema),
742 "keyref" => xsd_parse_identity_constraint(node, XsdComponentType::KeyRef, schema),
743 "pattern" | "enumeration" | "minInclusive" | "maxInclusive" | "minExclusive"
745 | "maxExclusive" | "minLength" | "maxLength" | "length" | "whiteSpace"
746 | "fractionDigits" | "totalDigits" => xsd_parse_facet(node),
747 "simpleContent" => xsd_parse_simple_content(node, schema),
749 "complexContent" => xsd_parse_complex_content(node, schema),
750 _ => {
751 let mut comp = XsdComponent::new(XsdComponentType::Schema);
753 if let Ok(s) = std::str::from_utf8(std::slice::from_raw_parts((*node).name, {
754 let mut len = 0;
755 while *(*node).name.add(len) != 0 {
756 len += 1;
757 }
758 len
759 })) {
760 comp.name = Some(s.to_string());
761 }
762 comp
763 }
764 }
765 }
766}
767
768unsafe fn xsd_parse_element(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
774 unsafe {
775 let mut comp = XsdComponent::new(XsdComponentType::Element);
776 comp.name = get_attr(node, "name");
777 comp.ref_name = get_attr(node, "ref");
778 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
779 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
780 comp.is_abstract = get_attr_bool(node, "abstract");
781 comp.is_final = get_attr_bool(node, "final");
782 comp.substitution_group = get_attr(node, "substitutionGroup");
783 comp.form = get_attr(node, "form");
784
785 if let Some(type_name) = get_attr(node, "type") {
787 comp.datatype = parse_datatype_kind(&type_name);
788 if comp.datatype.is_none() {
790 comp.base = Some(type_name);
791 }
792 }
793
794 let _default = get_attr(node, "default");
796 let _fixed = get_attr(node, "fixed");
797
798 let mut child = (*node).children;
800 while !child.is_null() {
801 if (*child).type_ == XML_ELEMENT_NODE as c_int {
802 let child_comp = xsd_parse_component(child, schema);
803 match child_comp.component_type {
804 XsdComponentType::ComplexType | XsdComponentType::SimpleType => {
805 if let Some(ref name) = child_comp.name {
807 comp.base = Some(name.clone());
808 }
809 comp.children.push(child_comp);
810 }
811 XsdComponentType::Annotation => {
812 }
814 _ => {
815 comp.children.push(child_comp);
816 }
817 }
818 }
819 child = (*child).next;
820 }
821
822 comp
823 }
824}
825
826unsafe fn xsd_parse_attribute_node(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
832 unsafe {
833 let mut comp = XsdComponent::new(XsdComponentType::Attribute);
834 comp.name = get_attr(node, "name");
835 comp.ref_name = get_attr(node, "ref");
836 comp.form = get_attr(node, "form");
837
838 if let Some(type_name) = get_attr(node, "type") {
840 comp.datatype = parse_datatype_kind(&type_name);
841 if comp.datatype.is_none() {
842 comp.base = Some(type_name);
843 }
844 }
845
846 let use_attr = get_attr(node, "use");
848 if let Some(ref use_val) = use_attr {
849 if use_val == "required" {
850 comp.min_occurs = 1;
851 } else if use_val == "prohibited" {
852 comp.min_occurs = 0;
853 comp.max_occurs = 0;
854 } else {
855 comp.min_occurs = 0;
857 }
858 } else {
859 comp.min_occurs = 0; }
861
862 let _default = get_attr(node, "default");
863 let _fixed = get_attr(node, "fixed");
864
865 let mut child = (*node).children;
867 while !child.is_null() {
868 if (*child).type_ == XML_ELEMENT_NODE as c_int {
869 let child_comp = xsd_parse_component(child, schema);
870 if child_comp.component_type == XsdComponentType::SimpleType {
871 if let Some(ref name) = child_comp.name {
872 comp.base = Some(name.clone());
873 }
874 comp.children.push(child_comp);
875 }
876 }
877 child = (*child).next;
878 }
879
880 comp
881 }
882}
883
884unsafe fn xsd_parse_complex_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
890 unsafe {
891 let mut comp = XsdComponent::new(XsdComponentType::ComplexType);
892 comp.name = get_attr(node, "name");
893 comp.mixed = get_attr_bool(node, "mixed");
894 comp.is_abstract = get_attr_bool(node, "abstract");
895 comp.is_final = get_attr_bool(node, "final");
896
897 let mut child = (*node).children;
899 while !child.is_null() {
900 if (*child).type_ == XML_ELEMENT_NODE as c_int {
901 let child_comp = xsd_parse_component(child, schema);
902 match child_comp.component_type {
903 XsdComponentType::SimpleContent
904 | XsdComponentType::ComplexContent
905 | XsdComponentType::Sequence
906 | XsdComponentType::Choice
907 | XsdComponentType::All
908 | XsdComponentType::Group
909 | XsdComponentType::Any
910 | XsdComponentType::Annotation => {
911 if child_comp.component_type == XsdComponentType::SimpleContent {
912 comp.children.extend(child_comp.children);
914 } else if child_comp.component_type == XsdComponentType::ComplexContent {
915 comp.children.extend(child_comp.children);
917 } else {
918 comp.children.push(child_comp);
919 }
920 }
921 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
922 comp.attributes.push(child_comp);
923 }
924 _ => {
925 comp.children.push(child_comp);
926 }
927 }
928 }
929 child = (*child).next;
930 }
931
932 comp
933 }
934}
935
936unsafe fn xsd_parse_simple_type(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
942 unsafe {
943 let mut comp = XsdComponent::new(XsdComponentType::SimpleType);
944 comp.name = get_attr(node, "name");
945
946 let mut child = (*node).children;
948 while !child.is_null() {
949 if (*child).type_ == XML_ELEMENT_NODE as c_int {
950 let child_comp = xsd_parse_component(child, schema);
951 match child_comp.component_type {
952 XsdComponentType::Restriction
953 | XsdComponentType::List
954 | XsdComponentType::Union => {
955 comp.datatype = child_comp.datatype;
956 comp.base = child_comp.base;
957 comp.facets = child_comp.facets;
958 comp.children.extend(child_comp.children);
959 }
960 _ => {}
961 }
962 }
963 child = (*child).next;
964 }
965
966 comp
967 }
968}
969
970unsafe fn xsd_parse_model_group(
976 node: *mut _xmlNode,
977 ctype: XsdComponentType,
978 schema: &XsdSchema,
979) -> XsdComponent {
980 unsafe {
981 let mut comp = XsdComponent::new(ctype);
982 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
983 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
984
985 let mut child = (*node).children;
986 while !child.is_null() {
987 if (*child).type_ == XML_ELEMENT_NODE as c_int {
988 let child_comp = xsd_parse_component(child, schema);
989 match child_comp.component_type {
990 XsdComponentType::Annotation => {}
991 _ => {
992 comp.children.push(child_comp);
993 }
994 }
995 }
996 child = (*child).next;
997 }
998
999 comp
1000 }
1001}
1002
1003unsafe fn xsd_parse_restriction(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1009 unsafe {
1010 let mut comp = XsdComponent::new(XsdComponentType::Restriction);
1011 comp.base = get_attr(node, "base");
1012
1013 if let Some(ref base_name) = comp.base {
1015 comp.datatype = parse_datatype_kind(base_name);
1016 }
1017
1018 let mut child = (*node).children;
1020 while !child.is_null() {
1021 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1022 let child_comp = xsd_parse_component(child, schema);
1023 match child_comp.component_type {
1024 XsdComponentType::Sequence
1025 | XsdComponentType::Choice
1026 | XsdComponentType::All
1027 | XsdComponentType::Group
1028 | XsdComponentType::Any
1029 | XsdComponentType::Annotation => {
1030 comp.children.push(child_comp);
1031 }
1032 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1033 comp.attributes.push(child_comp);
1034 }
1035 XsdComponentType::SimpleType => {
1036 comp.children.push(child_comp);
1038 }
1039 _ => {
1040 if let Some(facet_kind) =
1042 parse_facet_kind(&format!("{:?}", child_comp.component_type))
1043 {
1044 if let Some(val) = get_attr(child, "value") {
1046 comp.facets.push((facet_kind, val));
1047 }
1048 }
1049 let name_str = if !(*child).name.is_null() {
1051 let mut len = 0;
1052 while *(*child).name.add(len) != 0 {
1053 len += 1;
1054 }
1055 let slice = std::slice::from_raw_parts((*child).name, len);
1056 std::str::from_utf8(slice)
1057 .ok()
1058 .map(|s| {
1059 if let Some(pos) = s.find(':') {
1060 s[pos + 1..].to_string()
1061 } else {
1062 s.to_string()
1063 }
1064 })
1065 .unwrap_or_default()
1066 } else {
1067 String::new()
1068 };
1069 if !name_str.is_empty() {
1070 if let Some(facet_kind) = parse_facet_kind(&name_str) {
1071 if let Some(val) = get_attr(child, "value") {
1072 comp.facets.push((facet_kind, val));
1073 }
1074 }
1075 }
1076 }
1077 }
1078 }
1079 child = (*child).next;
1080 }
1081
1082 comp
1083 }
1084}
1085
1086unsafe fn xsd_parse_extension(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1092 unsafe {
1093 let mut comp = XsdComponent::new(XsdComponentType::Extension);
1094 comp.base = get_attr(node, "base");
1095
1096 if let Some(ref base_name) = comp.base {
1097 comp.datatype = parse_datatype_kind(base_name);
1098 }
1099
1100 let mut child = (*node).children;
1102 while !child.is_null() {
1103 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1104 let child_comp = xsd_parse_component(child, schema);
1105 match child_comp.component_type {
1106 XsdComponentType::Sequence
1107 | XsdComponentType::Choice
1108 | XsdComponentType::All
1109 | XsdComponentType::Group
1110 | XsdComponentType::Any
1111 | XsdComponentType::Annotation => {
1112 comp.children.push(child_comp);
1113 }
1114 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1115 comp.attributes.push(child_comp);
1116 }
1117 _ => {}
1118 }
1119 }
1120 child = (*child).next;
1121 }
1122
1123 comp
1124 }
1125}
1126
1127unsafe fn xsd_parse_list(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1133 unsafe {
1134 let mut comp = XsdComponent::new(XsdComponentType::List);
1135
1136 if let Some(item_type) = get_attr(node, "itemType") {
1137 comp.base = Some(item_type.clone());
1138 comp.datatype = parse_datatype_kind(&item_type);
1139 }
1140
1141 let mut child = (*node).children;
1143 while !child.is_null() {
1144 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1145 let child_comp = xsd_parse_component(child, schema);
1146 if child_comp.component_type == XsdComponentType::SimpleType {
1147 comp.datatype = child_comp.datatype;
1148 comp.base = child_comp.base;
1149 comp.facets = child_comp.facets;
1150 }
1151 }
1152 child = (*child).next;
1153 }
1154
1155 comp
1156 }
1157}
1158
1159unsafe fn xsd_parse_union(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1165 unsafe {
1166 let mut comp = XsdComponent::new(XsdComponentType::Union);
1167
1168 if let Some(member_types) = get_attr(node, "memberTypes") {
1169 comp.base = Some(member_types);
1170 }
1171
1172 let mut child = (*node).children;
1173 while !child.is_null() {
1174 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1175 let child_comp = xsd_parse_component(child, schema);
1176 if child_comp.component_type == XsdComponentType::SimpleType {
1177 comp.children.push(child_comp);
1178 }
1179 }
1180 child = (*child).next;
1181 }
1182
1183 comp
1184 }
1185}
1186
1187unsafe fn xsd_parse_annotation(node: *mut _xmlNode) -> XsdComponent {
1193 unsafe {
1194 let mut comp = XsdComponent::new(XsdComponentType::Annotation);
1195
1196 let mut child = (*node).children;
1197 while !child.is_null() {
1198 if (*child).type_ == XML_ELEMENT_NODE as c_int
1199 && (node_is(child, "documentation") || node_is(child, "appinfo"))
1200 {
1201 let text = get_node_text(child);
1202 if !text.is_empty() {
1203 comp.facets.push((XsdDatatypeKind::String, text));
1204 }
1205 }
1206 child = (*child).next;
1207 }
1208
1209 comp
1210 }
1211}
1212
1213unsafe fn xsd_parse_any(node: *mut _xmlNode, _schema: &XsdSchema) -> XsdComponent {
1219 unsafe {
1220 let mut comp = XsdComponent::new(XsdComponentType::Any);
1221 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1222 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1223
1224 let namespace_attr = get_attr(node, "namespace");
1225 if let Some(ref ns) = namespace_attr {
1226 if ns != "##any" {
1227 comp.target_namespace = Some(ns.clone());
1228 }
1229 }
1230
1231 comp
1232 }
1233}
1234
1235unsafe fn xsd_parse_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1241 unsafe {
1242 let mut comp = XsdComponent::new(XsdComponentType::Group);
1243 comp.name = get_attr(node, "name");
1244 comp.ref_name = get_attr(node, "ref");
1245 comp.min_occurs = get_attr_occurs(node, "minOccurs", 1);
1246 comp.max_occurs = get_attr_occurs(node, "maxOccurs", 1);
1247
1248 let mut child = (*node).children;
1249 while !child.is_null() {
1250 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1251 let child_comp = xsd_parse_component(child, schema);
1252 match child_comp.component_type {
1253 XsdComponentType::Annotation => {}
1254 _ => {
1255 comp.children.push(child_comp);
1256 }
1257 }
1258 }
1259 child = (*child).next;
1260 }
1261
1262 comp
1263 }
1264}
1265
1266unsafe fn xsd_parse_attribute_group(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1272 unsafe {
1273 let mut comp = XsdComponent::new(XsdComponentType::AttributeGroup);
1274 comp.name = get_attr(node, "name");
1275 comp.ref_name = get_attr(node, "ref");
1276
1277 let mut child = (*node).children;
1278 while !child.is_null() {
1279 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1280 let child_comp = xsd_parse_component(child, schema);
1281 match child_comp.component_type {
1282 XsdComponentType::Attribute | XsdComponentType::AnyAttribute => {
1283 comp.attributes.push(child_comp);
1284 }
1285 _ => {}
1286 }
1287 }
1288 child = (*child).next;
1289 }
1290
1291 comp
1292 }
1293}
1294
1295unsafe fn xsd_parse_facet(node: *mut _xmlNode) -> XsdComponent {
1301 unsafe {
1302 let name_str = if !(*node).name.is_null() {
1303 let mut len = 0;
1304 while *(*node).name.add(len) != 0 {
1305 len += 1;
1306 }
1307 let slice = std::slice::from_raw_parts((*node).name, len);
1308 std::str::from_utf8(slice)
1309 .ok()
1310 .map(|s| {
1311 if let Some(pos) = s.find(':') {
1312 s[pos + 1..].to_string()
1313 } else {
1314 s.to_string()
1315 }
1316 })
1317 .unwrap_or_default()
1318 } else {
1319 String::new()
1320 };
1321
1322 let facet_kind = parse_facet_kind(&name_str).unwrap_or(XsdDatatypeKind::String);
1323 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1324 let val = get_attr(node, "value").unwrap_or_default();
1325 comp.facets.push((facet_kind, val));
1326 comp.datatype = Some(facet_kind);
1327
1328 comp
1329 }
1330}
1331
1332unsafe fn xsd_parse_simple_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1338 unsafe {
1339 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1340
1341 let mut child = (*node).children;
1342 while !child.is_null() {
1343 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1344 let child_comp = xsd_parse_component(child, schema);
1345 match child_comp.component_type {
1346 XsdComponentType::Restriction | XsdComponentType::Extension => {
1347 comp.children.push(child_comp);
1348 }
1349 _ => {}
1350 }
1351 }
1352 child = (*child).next;
1353 }
1354
1355 comp
1356 }
1357}
1358
1359unsafe fn xsd_parse_complex_content(node: *mut _xmlNode, schema: &XsdSchema) -> XsdComponent {
1365 unsafe {
1366 let mut comp = XsdComponent::new(XsdComponentType::Schema);
1367
1368 let mut child = (*node).children;
1369 while !child.is_null() {
1370 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1371 let child_comp = xsd_parse_component(child, schema);
1372 match child_comp.component_type {
1373 XsdComponentType::Restriction | XsdComponentType::Extension => {
1374 comp.children.push(child_comp);
1375 }
1376 _ => {}
1377 }
1378 }
1379 child = (*child).next;
1380 }
1381
1382 comp
1383 }
1384}
1385
1386unsafe fn xsd_parse_identity_constraint(
1392 node: *mut _xmlNode,
1393 ctype: XsdComponentType,
1394 schema: &XsdSchema,
1395) -> XsdComponent {
1396 unsafe {
1397 let mut comp = XsdComponent::new(ctype);
1398 comp.name = get_attr(node, "name");
1399
1400 if ctype == XsdComponentType::KeyRef {
1401 comp.ref_name = get_attr(node, "refer");
1402 }
1403
1404 let mut child = (*node).children;
1405 while !child.is_null() {
1406 if (*child).type_ == XML_ELEMENT_NODE as c_int {
1407 let child_comp = xsd_parse_component(child, schema);
1408 match child_comp.component_type {
1409 XsdComponentType::Selector | XsdComponentType::Field => {
1410 comp.children.push(child_comp);
1411 }
1412 _ => {}
1413 }
1414 }
1415 child = (*child).next;
1416 }
1417
1418 comp
1419 }
1420}
1421
1422pub fn xsd_validate_datatype(
1432 kind: &XsdDatatypeKind,
1433 value: &str,
1434 facets: &[(XsdDatatypeKind, String)],
1435) -> bool {
1436 if !validate_base_type(kind, value) {
1438 return false;
1439 }
1440
1441 let mut has_enumeration = false;
1446 let mut enumeration_match = false;
1447
1448 for (facet_kind, facet_value) in facets {
1449 if *facet_kind == XsdDatatypeKind::FacetEnumeration {
1450 has_enumeration = true;
1451 if xsd_validate_facet(kind, value, facet_kind, facet_value) {
1452 enumeration_match = true;
1453 }
1454 } else if !xsd_validate_facet(kind, value, facet_kind, facet_value) {
1455 return false;
1456 }
1457 }
1458
1459 if has_enumeration && !enumeration_match {
1461 return false;
1462 }
1463
1464 true
1465}
1466
1467pub fn xsd_validate_facet(
1469 _kind: &XsdDatatypeKind,
1470 value: &str,
1471 facet_kind: &XsdDatatypeKind,
1472 facet_value: &str,
1473) -> bool {
1474 match facet_kind {
1475 XsdDatatypeKind::FacetPattern => {
1476 match facet_value {
1479 r"\d+" => value.chars().all(|c| c.is_ascii_digit()),
1480 r"\d*" => value.is_empty() || value.chars().all(|c| c.is_ascii_digit()),
1481 r"[a-zA-Z]+" => value.chars().all(|c| c.is_ascii_alphabetic()),
1482 r"[a-zA-Z]*" => value.is_empty() || value.chars().all(|c| c.is_ascii_alphabetic()),
1483 r"[a-zA-Z0-9]+" => value.chars().all(|c| c.is_ascii_alphanumeric()),
1484 r"[a-zA-Z0-9_\-]+" => value
1485 .chars()
1486 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
1487 r"[a-zA-Z_][a-zA-Z0-9_\-\.]*" => {
1488 if value.is_empty() {
1489 return false;
1490 }
1491 let first = value.chars().next().unwrap();
1492 if !first.is_ascii_alphabetic() && first != '_' {
1493 return false;
1494 }
1495 value
1496 .chars()
1497 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1498 }
1499 r"[a-zA-Z_][\w\-\.]*" => {
1500 if value.is_empty() {
1501 return false;
1502 }
1503 let first = value.chars().next().unwrap();
1504 if !first.is_ascii_alphabetic() && first != '_' {
1505 return false;
1506 }
1507 value
1508 .chars()
1509 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
1510 }
1511 r"\i\c*" => {
1512 if value.is_empty() {
1514 return false;
1515 }
1516 let first = value.chars().next().unwrap();
1517 if !is_name_start_char(first) {
1518 return false;
1519 }
1520 value.chars().skip(1).all(is_name_char)
1521 }
1522 r"\c+" => {
1523 if value.is_empty() {
1524 return false;
1525 }
1526 value.chars().all(is_name_char)
1527 }
1528 _ => {
1530 if facet_value.starts_with('^') && facet_value.ends_with('$') {
1531 let inner = &facet_value[1..facet_value.len() - 1];
1532 simple_glob_match(inner, value)
1533 } else {
1534 true
1536 }
1537 }
1538 }
1539 }
1540 XsdDatatypeKind::FacetEnumeration => {
1541 value == facet_value
1543 }
1544 XsdDatatypeKind::FacetMinInclusive => {
1545 compare_strings(value, facet_value) != std::cmp::Ordering::Less
1546 }
1547 XsdDatatypeKind::FacetMaxInclusive => {
1548 compare_strings(value, facet_value) != std::cmp::Ordering::Greater
1549 }
1550 XsdDatatypeKind::FacetMinExclusive => {
1551 compare_strings(value, facet_value) == std::cmp::Ordering::Greater
1552 }
1553 XsdDatatypeKind::FacetMaxExclusive => {
1554 compare_strings(value, facet_value) == std::cmp::Ordering::Less
1555 }
1556 XsdDatatypeKind::FacetMinLength => {
1557 let min = facet_value.parse::<usize>().unwrap_or(0);
1558 value.chars().count() >= min
1559 }
1560 XsdDatatypeKind::FacetMaxLength => {
1561 let max = facet_value.parse::<usize>().unwrap_or(usize::MAX);
1562 value.chars().count() <= max
1563 }
1564 XsdDatatypeKind::FacetLength => {
1565 let len = facet_value.parse::<usize>().unwrap_or(0);
1566 value.chars().count() == len
1567 }
1568 XsdDatatypeKind::FacetWhiteSpace => {
1569 match facet_value {
1571 "replace" => {
1572 true
1575 }
1576 "collapse" => {
1577 true
1579 }
1580 _ => true,
1581 }
1582 }
1583 XsdDatatypeKind::FacetFractionDigits | XsdDatatypeKind::FacetTotalDigits => {
1584 value.parse::<f64>().is_ok()
1586 }
1587 _ => true,
1588 }
1589}
1590
1591fn simple_glob_match(pattern: &str, value: &str) -> bool {
1593 let pattern_chars: Vec<char> = pattern.chars().collect();
1594 let value_chars: Vec<char> = value.chars().collect();
1595
1596 let mut pi = 0;
1597 let mut vi = 0;
1598 let mut backtrack_p = None;
1599 let mut backtrack_v = 0;
1600
1601 while vi < value_chars.len() {
1602 if pi < pattern_chars.len()
1603 && (pattern_chars[pi] == value_chars[vi] || pattern_chars[pi] == '.')
1604 {
1605 pi += 1;
1606 vi += 1;
1607 } else if pi < pattern_chars.len() && pattern_chars[pi] == '*' {
1608 backtrack_p = Some(pi);
1609 backtrack_v = vi + 1;
1610 pi += 1;
1611 } else if pi < pattern_chars.len() && pattern_chars[pi] == '+' {
1612 if pi + 1 < pattern_chars.len() && pattern_chars[pi + 1] == value_chars[vi] {
1614 pi += 1;
1615 vi += 1;
1616 while vi < value_chars.len() && value_chars[vi] == pattern_chars[pi] {
1618 vi += 1;
1619 }
1620 pi += 1;
1621 } else {
1622 return false;
1623 }
1624 } else if let Some(bp) = backtrack_p {
1625 pi = bp + 1;
1626 vi = backtrack_v;
1627 backtrack_v += 1;
1628 } else {
1629 return false;
1630 }
1631 }
1632
1633 while pi < pattern_chars.len() && (pattern_chars[pi] == '*' || pattern_chars[pi] == '+') {
1635 if pattern_chars[pi] == '+' && vi == value_chars.len() {
1636 return false; }
1638 pi += 1;
1639 }
1640
1641 pi == pattern_chars.len()
1642}
1643
1644const fn is_name_start_char(c: char) -> bool {
1646 c.is_ascii_alphabetic()
1647 || c == '_'
1648 || c == ':'
1649 || (c >= '\u{00C0}' && c <= '\u{00D6}')
1650 || (c >= '\u{00D8}' && c <= '\u{00F6}')
1651 || (c >= '\u{00F8}' && c <= '\u{02FF}')
1652 || (c >= '\u{0370}' && c <= '\u{037D}')
1653 || (c >= '\u{037F}' && c <= '\u{1FFF}')
1654 || (c >= '\u{200C}' && c <= '\u{200D}')
1655 || (c >= '\u{2070}' && c <= '\u{218F}')
1656 || (c >= '\u{2C00}' && c <= '\u{2FEF}')
1657 || (c >= '\u{3001}' && c <= '\u{D7FF}')
1658 || (c >= '\u{F900}' && c <= '\u{FDCF}')
1659 || (c >= '\u{FDF0}' && c <= '\u{FFFD}')
1660}
1661
1662const fn is_name_char(c: char) -> bool {
1664 is_name_start_char(c)
1665 || c.is_ascii_digit()
1666 || c == '-'
1667 || c == '.'
1668 || c == '\u{00B7}'
1669 || (c >= '\u{0300}' && c <= '\u{036F}')
1670 || (c >= '\u{203F}' && c <= '\u{2040}')
1671}
1672
1673fn compare_strings(a: &str, b: &str) -> std::cmp::Ordering {
1675 if let (Ok(na), Ok(nb)) = (a.parse::<f64>(), b.parse::<f64>()) {
1677 return na.partial_cmp(&nb).unwrap_or(std::cmp::Ordering::Equal);
1678 }
1679 if let (Ok(na), Ok(nb)) = (a.parse::<i64>(), b.parse::<i64>()) {
1681 return na.cmp(&nb);
1682 }
1683 a.cmp(b)
1685}
1686
1687fn validate_base_type(kind: &XsdDatatypeKind, value: &str) -> bool {
1689 match kind {
1690 XsdDatatypeKind::String => true,
1691 XsdDatatypeKind::NormalizedString => {
1692 !value.contains('\t') && !value.contains('\n') && !value.contains('\r')
1694 }
1695 XsdDatatypeKind::Token => {
1696 if value.is_empty() {
1698 return true;
1699 }
1700 if value.starts_with(' ') || value.ends_with(' ') {
1701 return false;
1702 }
1703 !value.contains(" ")
1704 && !value.contains('\t')
1705 && !value.contains('\n')
1706 && !value.contains('\r')
1707 }
1708 XsdDatatypeKind::Language => {
1709 if value.is_empty() {
1712 return false;
1713 }
1714 let segments: Vec<&str> = value.split('-').collect();
1715 if segments.is_empty() {
1716 return false;
1717 }
1718 if segments[0].is_empty() || !segments[0].chars().all(|c| c.is_ascii_alphabetic()) {
1720 return false;
1721 }
1722 if segments[0].len() > 8 {
1723 return false;
1724 }
1725 for seg in &segments[1..] {
1727 if seg.is_empty() || seg.len() > 8 {
1728 return false;
1729 }
1730 if !seg.chars().all(|c| c.is_ascii_alphanumeric()) {
1731 return false;
1732 }
1733 }
1734 true
1735 }
1736 XsdDatatypeKind::Name => {
1737 if value.is_empty() {
1738 return false;
1739 }
1740 let mut chars = value.chars();
1741 let first = chars.next().unwrap();
1742 if !is_name_start_char(first) {
1743 return false;
1744 }
1745 chars.all(is_name_char)
1746 }
1747 XsdDatatypeKind::NCName
1748 | XsdDatatypeKind::Id
1749 | XsdDatatypeKind::Idref
1750 | XsdDatatypeKind::Entity => {
1751 if value.is_empty() || value.contains(':') {
1753 return false;
1754 }
1755 let mut chars = value.chars();
1756 let first = chars.next().unwrap();
1757 if !is_name_start_char(first) {
1758 return false;
1759 }
1760 chars.all(is_name_char)
1761 }
1762 XsdDatatypeKind::Boolean => {
1763 matches!(value, "true" | "false" | "1" | "0")
1764 }
1765 XsdDatatypeKind::Decimal
1766 | XsdDatatypeKind::Integer
1767 | XsdDatatypeKind::NonPositiveInteger
1768 | XsdDatatypeKind::NegativeInteger
1769 | XsdDatatypeKind::Long
1770 | XsdDatatypeKind::Int
1771 | XsdDatatypeKind::Short
1772 | XsdDatatypeKind::Byte
1773 | XsdDatatypeKind::NonNegativeInteger
1774 | XsdDatatypeKind::UnsignedLong
1775 | XsdDatatypeKind::UnsignedInt
1776 | XsdDatatypeKind::UnsignedShort
1777 | XsdDatatypeKind::UnsignedByte
1778 | XsdDatatypeKind::PositiveInteger => {
1779 if value.is_empty() {
1781 return false;
1782 }
1783 let mut chars = value.chars().peekable();
1784 if *chars.peek().unwrap_or(&'\0') == '-' || *chars.peek().unwrap_or(&'\0') == '+' {
1785 chars.next();
1786 }
1787 let mut has_dot = false;
1788 let mut has_digit = false;
1789 for c in chars {
1790 if c == '.' {
1791 if has_dot {
1792 return false;
1793 }
1794 has_dot = true;
1795 } else if c.is_ascii_digit() {
1796 has_digit = true;
1797 } else {
1798 return false;
1799 }
1800 }
1801 if !has_digit {
1802 return false;
1803 }
1804
1805 if has_dot && *kind != XsdDatatypeKind::Decimal {
1808 return false;
1809 }
1810
1811 match kind {
1812 XsdDatatypeKind::NonPositiveInteger => {
1813 if let Ok(v) = value.parse::<i64>() {
1814 v <= 0
1815 } else {
1816 false
1817 }
1818 }
1819 XsdDatatypeKind::NegativeInteger => {
1820 if let Ok(v) = value.parse::<i64>() {
1821 v < 0
1822 } else {
1823 false
1824 }
1825 }
1826 XsdDatatypeKind::NonNegativeInteger => {
1827 if let Ok(v) = value.parse::<i64>() {
1828 v >= 0
1829 } else {
1830 false
1831 }
1832 }
1833 XsdDatatypeKind::PositiveInteger => {
1834 if let Ok(v) = value.parse::<i64>() {
1835 v > 0
1836 } else {
1837 false
1838 }
1839 }
1840 XsdDatatypeKind::UnsignedLong
1841 | XsdDatatypeKind::UnsignedInt
1842 | XsdDatatypeKind::UnsignedShort
1843 | XsdDatatypeKind::UnsignedByte => {
1844 if let Ok(v) = value.parse::<u64>() {
1845 match kind {
1846 XsdDatatypeKind::UnsignedInt => v <= u64::from(u32::MAX),
1847 XsdDatatypeKind::UnsignedShort => v <= u64::from(u16::MAX),
1848 XsdDatatypeKind::UnsignedByte => v <= u64::from(u8::MAX),
1849 _ => true,
1850 }
1851 } else {
1852 false
1853 }
1854 }
1855 XsdDatatypeKind::Long => value.parse::<i64>().is_ok(),
1856 XsdDatatypeKind::Int => value.parse::<i32>().is_ok(),
1857 XsdDatatypeKind::Short => value.parse::<i16>().is_ok(),
1858 XsdDatatypeKind::Byte => value.parse::<i8>().is_ok(),
1859 _ => true,
1860 }
1861 }
1862 XsdDatatypeKind::Float | XsdDatatypeKind::Double => {
1863 matches!(value, "INF" | "-INF" | "NaN") || value.parse::<f64>().is_ok()
1865 }
1866 XsdDatatypeKind::Duration => {
1867 if !value.starts_with('-') && !value.starts_with('P') {
1869 return false;
1870 }
1871 let dur = value.strip_prefix('-').unwrap_or(value);
1872 if !dur.starts_with('P') {
1873 return false;
1874 }
1875 let rest = &dur[1..];
1876 if rest.is_empty() {
1877 return false;
1878 }
1879 let has_t = rest.contains('T');
1880 let _date_part = if has_t {
1881 &rest[..rest.find('T').unwrap()]
1882 } else {
1883 rest
1884 };
1885 if has_t {
1886 let time_part = &rest[rest.find('T').unwrap() + 1..];
1887 if time_part.is_empty() {
1888 return false;
1889 }
1890 }
1891 true
1892 }
1893 XsdDatatypeKind::DateTime => {
1894 if value.len() < 19 {
1896 return false;
1897 }
1898 let chars: Vec<char> = value.chars().collect();
1899 chars[4] == '-'
1900 && chars[7] == '-'
1901 && chars[10] == 'T'
1902 && chars[13] == ':'
1903 && chars[16] == ':'
1904 }
1905 XsdDatatypeKind::Date => {
1906 if value.len() < 10 {
1908 return false;
1909 }
1910 let chars: Vec<char> = value.chars().collect();
1911 chars[4] == '-' && chars[7] == '-'
1912 }
1913 XsdDatatypeKind::Time => {
1914 if value.len() < 8 {
1916 return false;
1917 }
1918 let chars: Vec<char> = value.chars().collect();
1919 chars[2] == ':' && chars[5] == ':'
1920 }
1921 XsdDatatypeKind::GYear => {
1922 if value.len() < 4 {
1924 return false;
1925 }
1926 value.chars().take(4).all(|c| c.is_ascii_digit())
1927 }
1928 XsdDatatypeKind::GYearMonth => {
1929 if value.len() < 7 {
1931 return false;
1932 }
1933 let chars: Vec<char> = value.chars().collect();
1934 chars[4] == '-'
1935 }
1936 XsdDatatypeKind::GMonthDay => {
1937 if value.len() < 6 || !value.starts_with("--") {
1939 return false;
1940 }
1941 let chars: Vec<char> = value.chars().collect();
1942 chars[4] == '-'
1943 }
1944 XsdDatatypeKind::GDay => {
1945 value.starts_with("---") && value.len() >= 4
1947 }
1948 XsdDatatypeKind::GMonth => {
1949 value.starts_with("--") && value.len() >= 3
1951 }
1952 XsdDatatypeKind::HexBinary => {
1953 if !value.len().is_multiple_of(2) {
1954 return false;
1955 }
1956 value.chars().all(|c| c.is_ascii_hexdigit())
1957 }
1958 XsdDatatypeKind::Base64Binary => {
1959 if value.is_empty() {
1961 return true;
1962 }
1963 let valid_chars =
1964 |c: char| c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=';
1965 value.chars().all(valid_chars)
1966 }
1967 XsdDatatypeKind::AnyURI => {
1968 !value.is_empty()
1970 }
1971 XsdDatatypeKind::QName => {
1972 if let Some(pos) = value.find(':') {
1974 let prefix = &value[..pos];
1975 let local = &value[pos + 1..];
1976 is_ncname(prefix) && is_ncname(local)
1977 } else {
1978 is_ncname(value)
1979 }
1980 }
1981 XsdDatatypeKind::Notation => {
1982 !value.is_empty()
1984 }
1985 XsdDatatypeKind::Nmtoken => !value.is_empty() && value.chars().all(is_name_char),
1986 XsdDatatypeKind::Nmtokens => {
1987 !value.is_empty()
1988 && value
1989 .split_whitespace()
1990 .all(|t| !t.is_empty() && t.chars().all(is_name_char))
1991 }
1992 XsdDatatypeKind::Idrefs | XsdDatatypeKind::Entities => {
1993 !value.is_empty() && value.split_whitespace().all(is_ncname)
1994 }
1995 XsdDatatypeKind::FacetPattern
1997 | XsdDatatypeKind::FacetEnumeration
1998 | XsdDatatypeKind::FacetMinInclusive
1999 | XsdDatatypeKind::FacetMaxInclusive
2000 | XsdDatatypeKind::FacetMinExclusive
2001 | XsdDatatypeKind::FacetMaxExclusive
2002 | XsdDatatypeKind::FacetMinLength
2003 | XsdDatatypeKind::FacetMaxLength
2004 | XsdDatatypeKind::FacetLength
2005 | XsdDatatypeKind::FacetWhiteSpace
2006 | XsdDatatypeKind::FacetFractionDigits
2007 | XsdDatatypeKind::FacetTotalDigits => true,
2008 }
2009}
2010
2011fn is_ncname(value: &str) -> bool {
2013 if value.is_empty() {
2014 return false;
2015 }
2016 let first = value.chars().next().unwrap();
2017 if !is_name_start_char(first) || first == ':' {
2018 return false;
2019 }
2020 value.chars().skip(1).all(|c| is_name_char(c) && c != ':')
2021}
2022
2023pub fn xsd_validate(schema: &XsdSchema, doc: &str) -> Result<(), Vec<String>> {
2033 let doc_ptr = unsafe {
2034 crate::abi::exports_xml2::xmlReadMemory(
2035 doc.as_ptr() as *const c_char,
2036 doc.len() as c_int,
2037 c"doc.xml".as_ptr() as *const c_char,
2038 ptr::null(),
2039 0,
2040 )
2041 };
2042
2043 if doc_ptr.is_null() {
2044 return Err(vec!["Failed to parse XML document".to_string()]);
2045 }
2046
2047 let mut ctxt = XsdValidCtxt::new();
2048 ctxt.schema = Some(schema.clone());
2049
2050 let result = unsafe { xsd_validate_doc(schema, doc_ptr, &mut ctxt) };
2051
2052 unsafe {
2053 crate::abi::exports_xml2::xmlFreeDoc(doc_ptr);
2054 }
2055
2056 if result {
2057 Ok(())
2058 } else {
2059 Err(ctxt.errors)
2060 }
2061}
2062
2063unsafe fn xsd_validate_doc(schema: &XsdSchema, doc: *mut _xmlDoc, ctxt: &mut XsdValidCtxt) -> bool {
2069 unsafe {
2070 let root = (*doc).children;
2071 if root.is_null() {
2072 ctxt.errors.push("Document has no root element".to_string());
2073 ctxt.nb_errors += 1;
2074 return false;
2075 }
2076
2077 let mut root_elem = root;
2079 while !root_elem.is_null() && (*root_elem).type_ != XML_ELEMENT_NODE as c_int {
2080 root_elem = (*root_elem).next;
2081 }
2082
2083 if root_elem.is_null() {
2084 ctxt.errors.push("Document has no root element".to_string());
2085 ctxt.nb_errors += 1;
2086 return false;
2087 }
2088
2089 let root_name = get_node_qname(root_elem);
2091
2092 let global_elem = schema.components.iter().find(|c| {
2094 c.component_type == XsdComponentType::Element && c.name.as_deref() == Some(&root_name)
2095 });
2096
2097 if let Some(global) = global_elem {
2098 xsd_validate_element(global, root_elem, schema, ctxt)
2099 } else {
2100 let mut valid = true;
2102 for component in &schema.components {
2103 if component.component_type == XsdComponentType::Element {
2104 if let Some(ref name) = component.name {
2105 if *name == root_name {
2106 valid = xsd_validate_element(component, root_elem, schema, ctxt);
2107 break;
2108 }
2109 }
2110 }
2111 }
2112 valid
2113 }
2114 }
2115}
2116
2117fn xsd_validate_element(
2123 component: &XsdComponent,
2124 node: *mut _xmlNode,
2125 schema: &XsdSchema,
2126 ctxt: &mut XsdValidCtxt,
2127) -> bool {
2128 unsafe {
2129 let mut valid = true;
2130
2131 let node_name = get_node_qname(node);
2133
2134 if let Some(ref comp_name) = component.name {
2136 if comp_name != &node_name {
2137 ctxt.errors.push(format!(
2138 "Element '{}' does not match expected '{}'",
2139 node_name, comp_name
2140 ));
2141 ctxt.nb_errors += 1;
2142 return false;
2143 }
2144 }
2145
2146 let type_comp = component.children.iter().find(|c| {
2148 c.component_type == XsdComponentType::ComplexType
2149 || c.component_type == XsdComponentType::SimpleType
2150 });
2151
2152 if let Some(tc) = type_comp {
2153 match tc.component_type {
2154 XsdComponentType::ComplexType => {
2155 valid &= xsd_validate_complex_type(tc, node, schema, ctxt);
2156 }
2157 XsdComponentType::SimpleType => {
2158 let text = get_node_text(node);
2159 if let Some(ref dt) = tc.datatype {
2160 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2161 ctxt.errors.push(format!(
2162 "Element '{}' has invalid value '{}' for type '{:?}'",
2163 node_name, text, dt
2164 ));
2165 ctxt.nb_errors += 1;
2166 valid = false;
2167 }
2168 }
2169 }
2170 _ => {}
2171 }
2172 } else if let Some(ref dt) = component.datatype {
2173 let text = get_node_text(node);
2175 if !xsd_validate_datatype(dt, &text, &component.facets) {
2176 ctxt.errors.push(format!(
2177 "Element '{}' has invalid value '{}' for type '{:?}'",
2178 node_name, text, dt
2179 ));
2180 ctxt.nb_errors += 1;
2181 valid = false;
2182 }
2183 } else {
2184 valid &= xsd_validate_content(component, node, schema, ctxt);
2186 }
2187
2188 valid
2189 }
2190}
2191
2192fn xsd_validate_complex_type(
2198 component: &XsdComponent,
2199 node: *mut _xmlNode,
2200 schema: &XsdSchema,
2201 ctxt: &mut XsdValidCtxt,
2202) -> bool {
2203 {
2204 let mut valid = true;
2205
2206 for attr in &component.attributes {
2208 match attr.component_type {
2209 XsdComponentType::Attribute => {
2210 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2211 }
2212 XsdComponentType::AnyAttribute => {
2213 }
2215 _ => {}
2216 }
2217 }
2218
2219 for child in &component.children {
2221 match child.component_type {
2222 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2223 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2224 }
2225 XsdComponentType::Restriction | XsdComponentType::Extension => {
2226 valid &= xsd_validate_restriction_extension(child, node, schema, ctxt);
2228 }
2229 XsdComponentType::Any => {
2230 }
2232 _ => {}
2233 }
2234 }
2235
2236 valid
2237 }
2238}
2239
2240fn xsd_validate_model_group(
2246 component: &XsdComponent,
2247 node: *mut _xmlNode,
2248 _schema: &XsdSchema,
2249 ctxt: &mut XsdValidCtxt,
2250) -> bool {
2251 unsafe {
2252 let mut valid = true;
2253
2254 let mut child_nodes: Vec<*mut _xmlNode> = Vec::new();
2256 let mut child = (*node).children;
2257 while !child.is_null() {
2258 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2259 child_nodes.push(child);
2260 }
2261 child = (*child).next;
2262 }
2263
2264 match component.component_type {
2265 XsdComponentType::Sequence => {
2266 let mut child_idx = 0;
2268 for part in &component.children {
2269 let min = part.min_occurs;
2270 let max = part.max_occurs;
2271 let match_name = part.name.as_deref().unwrap_or("");
2272 let match_ref = part.ref_name.as_deref().unwrap_or("");
2273
2274 let mut count = 0;
2275 while child_idx < child_nodes.len() && (max == -1 || count < max) {
2276 let child_node = child_nodes[child_idx];
2277 let child_name = get_node_qname(child_node);
2278
2279 if part.component_type == XsdComponentType::Any
2280 || (!match_name.is_empty() && child_name == match_name)
2281 || (!match_ref.is_empty() && child_name == match_ref)
2282 {
2283 count += 1;
2284 child_idx += 1;
2285 } else if count >= min {
2286 break;
2287 } else {
2288 ctxt.errors.push(format!(
2289 "Expected element '{}' but found '{}'",
2290 match_name, child_name
2291 ));
2292 ctxt.nb_errors += 1;
2293 valid = false;
2294 child_idx += 1;
2295 break;
2296 }
2297 }
2298
2299 if count < min {
2300 ctxt.errors.push(format!(
2301 "Element '{}' occurs {} times, minimum is {}",
2302 if match_name.is_empty() {
2303 "?"
2304 } else {
2305 match_name
2306 },
2307 count,
2308 min
2309 ));
2310 ctxt.nb_errors += 1;
2311 valid = false;
2312 }
2313 }
2314
2315 if child_idx < child_nodes.len() {
2317 let extra = get_node_qname(child_nodes[child_idx]);
2318 ctxt.errors
2319 .push(format!("Unexpected element '{}' in sequence", extra));
2320 ctxt.nb_errors += 1;
2321 valid = false;
2322 }
2323 }
2324 XsdComponentType::Choice => {
2325 let mut matched = false;
2327 for child_node in &child_nodes {
2328 let child_name = get_node_qname(*child_node);
2329 for part in &component.children {
2330 let match_name = part.name.as_deref().unwrap_or("");
2331 let match_ref = part.ref_name.as_deref().unwrap_or("");
2332
2333 if part.component_type == XsdComponentType::Any {
2334 matched = true;
2335 } else if (!match_name.is_empty() && child_name == match_name)
2336 || (!match_ref.is_empty() && child_name == match_ref)
2337 {
2338 matched = true;
2339 break;
2340 }
2341 }
2342 if !matched {
2343 ctxt.errors
2344 .push(format!("Element '{}' is not valid in choice", child_name));
2345 ctxt.nb_errors += 1;
2346 valid = false;
2347 }
2348 matched = false; }
2350 }
2351 XsdComponentType::All => {
2352 for child_node in &child_nodes {
2354 let child_name = get_node_qname(*child_node);
2355 let mut matched = false;
2356 for part in &component.children {
2357 let match_name = part.name.as_deref().unwrap_or("");
2358 if !match_name.is_empty() && child_name == match_name {
2359 matched = true;
2360 break;
2361 }
2362 }
2363 if !matched {
2364 ctxt.errors.push(format!(
2365 "Element '{}' is not valid in all group",
2366 child_name
2367 ));
2368 ctxt.nb_errors += 1;
2369 valid = false;
2370 }
2371 }
2372 }
2373 _ => {}
2374 }
2375
2376 valid
2377 }
2378}
2379
2380fn xsd_validate_restriction_extension(
2386 component: &XsdComponent,
2387 node: *mut _xmlNode,
2388 schema: &XsdSchema,
2389 ctxt: &mut XsdValidCtxt,
2390) -> bool {
2391 unsafe {
2392 let mut valid = true;
2393
2394 for attr in &component.attributes {
2396 if attr.component_type == XsdComponentType::Attribute {
2397 valid &= xsd_validate_attribute(attr, node, schema, ctxt);
2398 }
2399 }
2400
2401 for child in &component.children {
2403 match child.component_type {
2404 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2405 valid &= xsd_validate_model_group(child, node, schema, ctxt);
2406 }
2407 _ => {}
2408 }
2409 }
2410
2411 if let Some(ref dt) = component.datatype {
2413 let text = get_node_text(node);
2414 if !xsd_validate_datatype(dt, &text, &component.facets) {
2415 let node_name = get_node_qname(node);
2416 ctxt.errors.push(format!(
2417 "Element '{}' has invalid value '{}' for type '{:?}'",
2418 node_name, text, dt
2419 ));
2420 ctxt.nb_errors += 1;
2421 valid = false;
2422 }
2423 }
2424
2425 valid
2426 }
2427}
2428
2429fn xsd_validate_attribute(
2435 component: &XsdComponent,
2436 node: *mut _xmlNode,
2437 _schema: &XsdSchema,
2438 ctxt: &mut XsdValidCtxt,
2439) -> bool {
2440 unsafe {
2441 let attr_name = component.name.as_deref().unwrap_or("");
2442 if attr_name.is_empty() {
2443 return true;
2444 }
2445
2446 let attr_value = get_attr(node, attr_name);
2448
2449 let is_required = component.min_occurs > 0;
2450
2451 match attr_value {
2452 Some(ref val) => {
2453 if let Some(ref dt) = component.datatype {
2455 if !xsd_validate_datatype(dt, val, &component.facets) {
2456 ctxt.errors.push(format!(
2457 "Attribute '{}' has invalid value '{}' for type '{:?}'",
2458 attr_name, val, dt
2459 ));
2460 ctxt.nb_errors += 1;
2461 return false;
2462 }
2463 }
2464 true
2465 }
2466 None => {
2467 if is_required {
2468 ctxt.errors
2469 .push(format!("Required attribute '{}' is missing", attr_name));
2470 ctxt.nb_errors += 1;
2471 false
2472 } else {
2473 true
2474 }
2475 }
2476 }
2477 }
2478}
2479
2480fn xsd_validate_content(
2486 component: &XsdComponent,
2487 node: *mut _xmlNode,
2488 schema: &XsdSchema,
2489 ctxt: &mut XsdValidCtxt,
2490) -> bool {
2491 {
2492 let mut valid = true;
2493
2494 for child_comp in &component.children {
2495 match child_comp.component_type {
2496 XsdComponentType::Sequence | XsdComponentType::Choice | XsdComponentType::All => {
2497 valid &= xsd_validate_model_group(child_comp, node, schema, ctxt);
2498 }
2499 XsdComponentType::Element => {
2500 valid &= xsd_validate_element_inline(child_comp, node, schema, ctxt);
2502 }
2503 _ => {}
2504 }
2505 }
2506
2507 valid
2508 }
2509}
2510
2511fn xsd_validate_element_inline(
2517 component: &XsdComponent,
2518 node: *mut _xmlNode,
2519 schema: &XsdSchema,
2520 ctxt: &mut XsdValidCtxt,
2521) -> bool {
2522 unsafe {
2523 let mut valid = true;
2524 let mut child = (*node).children;
2525
2526 while !child.is_null() {
2527 if (*child).type_ == XML_ELEMENT_NODE as c_int {
2528 let child_name = get_node_qname(child);
2529
2530 let match_name = component.name.as_deref().unwrap_or("");
2531 let match_ref = component.ref_name.as_deref().unwrap_or("");
2532
2533 if (!match_name.is_empty() && child_name == match_name)
2534 || (!match_ref.is_empty() && child_name == match_ref)
2535 {
2536 let type_comp = component.children.iter().find(|c| {
2538 c.component_type == XsdComponentType::ComplexType
2539 || c.component_type == XsdComponentType::SimpleType
2540 });
2541
2542 if let Some(tc) = type_comp {
2543 match tc.component_type {
2544 XsdComponentType::ComplexType => {
2545 valid &= xsd_validate_complex_type(tc, child, schema, ctxt);
2546 }
2547 XsdComponentType::SimpleType => {
2548 let text = get_node_text(child);
2549 if let Some(ref dt) = tc.datatype {
2550 if !xsd_validate_datatype(dt, &text, &tc.facets) {
2551 ctxt.errors.push(format!(
2552 "Element '{}' has invalid value '{}'",
2553 child_name, text
2554 ));
2555 ctxt.nb_errors += 1;
2556 valid = false;
2557 }
2558 }
2559 }
2560 _ => {}
2561 }
2562 }
2563 }
2564 }
2565 child = (*child).next;
2566 }
2567
2568 valid
2569 }
2570}
2571
2572unsafe fn get_node_qname(node: *mut _xmlNode) -> String {
2578 if node.is_null() {
2579 return String::new();
2580 }
2581 unsafe {
2582 let ns = (*node).ns;
2584 let prefix = if !ns.is_null() && !(*ns).prefix.is_null() {
2585 let mut len = 0;
2586 while *(*ns).prefix.add(len) != 0 {
2587 len += 1;
2588 }
2589 let slice = std::slice::from_raw_parts((*ns).prefix, len);
2590 if let Ok(s) = std::str::from_utf8(slice) {
2591 format!("{}:", s)
2592 } else {
2593 String::new()
2594 }
2595 } else {
2596 String::new()
2597 };
2598
2599 let name = (*node).name;
2600 if name.is_null() {
2601 return String::new();
2602 }
2603 let mut len = 0;
2604 while *name.add(len) != 0 {
2605 len += 1;
2606 }
2607 let slice = std::slice::from_raw_parts(name, len);
2608 if let Ok(s) = std::str::from_utf8(slice) {
2609 format!("{}{}", prefix, s)
2610 } else {
2611 String::new()
2612 }
2613 }
2614}
2615
2616#[no_mangle]
2635pub unsafe extern "C" fn xmlSchemaNewParserCtxt(url: *const c_char) -> *mut c_void {
2636 if url.is_null() {
2637 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2639 return ctxt;
2640 }
2641
2642 let url_str = unsafe {
2644 if url.is_null() {
2645 String::new()
2646 } else {
2647 let mut len = 0;
2648 while *url.add(len) != 0 {
2649 len += 1;
2650 }
2651 let slice = std::slice::from_raw_parts(url as *const u8, len);
2652 String::from_utf8_lossy(slice).to_string()
2653 }
2654 };
2655
2656 let ctxt = allocator::xmlMallocZero(size_of::<XsdSchema>() as usize);
2659 if !url_str.is_empty() {
2661 let _ = url_str;
2663 }
2664
2665 ctxt
2666}
2667
2668#[no_mangle]
2680pub unsafe extern "C" fn xmlSchemaNewMemParserCtxt(
2681 buffer: *const c_char,
2682 size: c_int,
2683) -> *mut c_void {
2684 if buffer.is_null() || size <= 0 {
2685 return ptr::null_mut();
2686 }
2687
2688 let buf_slice = unsafe { std::slice::from_raw_parts(buffer as *const u8, size as usize) };
2690 let xml_str = String::from_utf8_lossy(buf_slice).to_string();
2691
2692 match xsd_parse(&xml_str) {
2693 Ok(schema) => {
2694 let schema_box = Box::new(schema);
2696 Box::into_raw(schema_box) as *mut c_void
2697 }
2698 Err(_) => ptr::null_mut(),
2699 }
2700}
2701
2702#[no_mangle]
2714pub const unsafe extern "C" fn xmlSchemaParse(ctxt: *mut c_void) -> *mut c_void {
2715 if ctxt.is_null() {
2716 return ptr::null_mut();
2717 }
2718
2719 ctxt
2723}
2724
2725#[no_mangle]
2737pub unsafe extern "C" fn xmlSchemaFree(schema: *mut c_void) {
2738 if schema.is_null() {
2739 return;
2740 }
2741 unsafe {
2743 let _ = Box::from_raw(schema as *mut XsdSchema);
2744 }
2745}
2746
2747#[no_mangle]
2762pub unsafe extern "C" fn xmlSchemaValidateDoc(ctxt: *mut c_void, doc: *mut _xmlDoc) -> c_int {
2763 if ctxt.is_null() || doc.is_null() {
2764 return -1;
2765 }
2766
2767 unsafe {
2768 let valid_ctxt = &mut *(ctxt as *mut XsdValidCtxt);
2769 let schema = match &valid_ctxt.schema {
2770 Some(s) => s,
2771 None => return -1,
2772 };
2773
2774 let mut temp_ctxt = XsdValidCtxt::new();
2775 temp_ctxt.schema = Some(schema.clone());
2776
2777 let valid = xsd_validate_doc(schema, doc, &mut temp_ctxt);
2778
2779 if valid {
2780 0
2781 } else {
2782 valid_ctxt.errors = temp_ctxt.errors;
2783 valid_ctxt.nb_errors = temp_ctxt.nb_errors;
2784 temp_ctxt.nb_errors
2785 }
2786 }
2787}
2788
2789#[no_mangle]
2801pub unsafe extern "C" fn xmlSchemaFreeParserCtxt(ctxt: *mut c_void) {
2802 if ctxt.is_null() {
2803 return;
2804 }
2805 unsafe {
2807 let _ = Box::from_raw(ctxt as *mut XsdSchema);
2808 }
2809}
2810
2811#[no_mangle]
2823pub unsafe extern "C" fn xmlSchemaFreeValidCtxt(ctxt: *mut c_void) {
2824 if ctxt.is_null() {
2825 return;
2826 }
2827 unsafe {
2829 let _ = Box::from_raw(ctxt as *mut XsdValidCtxt);
2830 }
2831}
2832
2833#[no_mangle]
2845pub unsafe extern "C" fn xmlSchemaNewValidCtxt(schema: *mut c_void) -> *mut c_void {
2846 let mut ctxt = XsdValidCtxt::new();
2847
2848 if !schema.is_null() {
2849 unsafe {
2851 let schema_ref = &*(schema as *const XsdSchema);
2852 ctxt.schema = Some(schema_ref.clone());
2853 }
2854 }
2855
2856 let boxed = Box::new(ctxt);
2857 Box::into_raw(boxed) as *mut c_void
2858}
2859
2860#[cfg(test)]
2865mod tests {
2866 use super::*;
2867
2868 #[test]
2871 fn test_validate_string() {
2872 assert!(xsd_validate_datatype(
2873 &XsdDatatypeKind::String,
2874 "hello",
2875 &[]
2876 ));
2877 assert!(xsd_validate_datatype(&XsdDatatypeKind::String, "", &[]));
2878 }
2879
2880 #[test]
2881 fn test_validate_boolean() {
2882 assert!(xsd_validate_datatype(
2883 &XsdDatatypeKind::Boolean,
2884 "true",
2885 &[]
2886 ));
2887 assert!(xsd_validate_datatype(
2888 &XsdDatatypeKind::Boolean,
2889 "false",
2890 &[]
2891 ));
2892 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "1", &[]));
2893 assert!(xsd_validate_datatype(&XsdDatatypeKind::Boolean, "0", &[]));
2894 assert!(!xsd_validate_datatype(
2895 &XsdDatatypeKind::Boolean,
2896 "yes",
2897 &[]
2898 ));
2899 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Boolean, "no", &[]));
2900 }
2901
2902 #[test]
2903 fn test_validate_integer() {
2904 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "42", &[]));
2905 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "-42", &[]));
2906 assert!(xsd_validate_datatype(&XsdDatatypeKind::Integer, "+42", &[]));
2907 assert!(!xsd_validate_datatype(
2908 &XsdDatatypeKind::Integer,
2909 "12.5",
2910 &[]
2911 ));
2912 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Integer, "", &[]));
2913 assert!(!xsd_validate_datatype(
2914 &XsdDatatypeKind::Integer,
2915 "abc",
2916 &[]
2917 ));
2918 }
2919
2920 #[test]
2921 fn test_validate_decimal() {
2922 assert!(xsd_validate_datatype(&XsdDatatypeKind::Decimal, "42", &[]));
2923 assert!(xsd_validate_datatype(
2924 &XsdDatatypeKind::Decimal,
2925 "12.5",
2926 &[]
2927 ));
2928 assert!(xsd_validate_datatype(
2929 &XsdDatatypeKind::Decimal,
2930 "-3.14",
2931 &[]
2932 ));
2933 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Decimal, "", &[]));
2934 }
2935
2936 #[test]
2937 fn test_validate_float() {
2938 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "3.14", &[]));
2939 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "INF", &[]));
2940 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "-INF", &[]));
2941 assert!(xsd_validate_datatype(&XsdDatatypeKind::Float, "NaN", &[]));
2942 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Float, "", &[]));
2943 }
2944
2945 #[test]
2946 fn test_validate_positive_integer() {
2947 assert!(xsd_validate_datatype(
2948 &XsdDatatypeKind::PositiveInteger,
2949 "1",
2950 &[]
2951 ));
2952 assert!(xsd_validate_datatype(
2953 &XsdDatatypeKind::PositiveInteger,
2954 "100",
2955 &[]
2956 ));
2957 assert!(!xsd_validate_datatype(
2958 &XsdDatatypeKind::PositiveInteger,
2959 "0",
2960 &[]
2961 ));
2962 assert!(!xsd_validate_datatype(
2963 &XsdDatatypeKind::PositiveInteger,
2964 "-1",
2965 &[]
2966 ));
2967 }
2968
2969 #[test]
2970 fn test_validate_non_negative_integer() {
2971 assert!(xsd_validate_datatype(
2972 &XsdDatatypeKind::NonNegativeInteger,
2973 "0",
2974 &[]
2975 ));
2976 assert!(xsd_validate_datatype(
2977 &XsdDatatypeKind::NonNegativeInteger,
2978 "42",
2979 &[]
2980 ));
2981 assert!(!xsd_validate_datatype(
2982 &XsdDatatypeKind::NonNegativeInteger,
2983 "-1",
2984 &[]
2985 ));
2986 }
2987
2988 #[test]
2989 fn test_validate_int_range() {
2990 assert!(xsd_validate_datatype(
2991 &XsdDatatypeKind::Int,
2992 "2147483647",
2993 &[]
2994 ));
2995 assert!(xsd_validate_datatype(
2996 &XsdDatatypeKind::Int,
2997 "-2147483648",
2998 &[]
2999 ));
3000 assert!(!xsd_validate_datatype(
3001 &XsdDatatypeKind::Int,
3002 "2147483648",
3003 &[]
3004 ));
3005 }
3006
3007 #[test]
3008 fn test_validate_short_range() {
3009 assert!(xsd_validate_datatype(&XsdDatatypeKind::Short, "32767", &[]));
3010 assert!(xsd_validate_datatype(
3011 &XsdDatatypeKind::Short,
3012 "-32768",
3013 &[]
3014 ));
3015 assert!(!xsd_validate_datatype(
3016 &XsdDatatypeKind::Short,
3017 "32768",
3018 &[]
3019 ));
3020 }
3021
3022 #[test]
3023 fn test_validate_byte_range() {
3024 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "127", &[]));
3025 assert!(xsd_validate_datatype(&XsdDatatypeKind::Byte, "-128", &[]));
3026 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Byte, "128", &[]));
3027 }
3028
3029 #[test]
3030 fn test_validate_date_time() {
3031 assert!(xsd_validate_datatype(
3032 &XsdDatatypeKind::DateTime,
3033 "2023-01-15T10:30:00",
3034 &[]
3035 ));
3036 assert!(!xsd_validate_datatype(
3037 &XsdDatatypeKind::DateTime,
3038 "not-a-date",
3039 &[]
3040 ));
3041 }
3042
3043 #[test]
3044 fn test_validate_date() {
3045 assert!(xsd_validate_datatype(
3046 &XsdDatatypeKind::Date,
3047 "2023-01-15",
3048 &[]
3049 ));
3050 assert!(!xsd_validate_datatype(
3051 &XsdDatatypeKind::Date,
3052 "2023/01/15",
3053 &[]
3054 ));
3055 }
3056
3057 #[test]
3058 fn test_validate_time() {
3059 assert!(xsd_validate_datatype(
3060 &XsdDatatypeKind::Time,
3061 "10:30:00",
3062 &[]
3063 ));
3064 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Time, "10:30", &[]));
3065 }
3066
3067 #[test]
3068 fn test_validate_hex_binary() {
3069 assert!(xsd_validate_datatype(
3070 &XsdDatatypeKind::HexBinary,
3071 "0FA1",
3072 &[]
3073 ));
3074 assert!(xsd_validate_datatype(&XsdDatatypeKind::HexBinary, "", &[]));
3075 assert!(!xsd_validate_datatype(
3076 &XsdDatatypeKind::HexBinary,
3077 "0FG1",
3078 &[]
3079 ));
3080 assert!(!xsd_validate_datatype(
3081 &XsdDatatypeKind::HexBinary,
3082 "0FA",
3083 &[]
3084 ));
3085 }
3086
3087 #[test]
3088 fn test_validate_base64() {
3089 assert!(xsd_validate_datatype(
3090 &XsdDatatypeKind::Base64Binary,
3091 "SGVsbG8=",
3092 &[]
3093 ));
3094 assert!(xsd_validate_datatype(
3095 &XsdDatatypeKind::Base64Binary,
3096 "",
3097 &[]
3098 ));
3099 assert!(!xsd_validate_datatype(
3100 &XsdDatatypeKind::Base64Binary,
3101 "Hello World!",
3102 &[]
3103 ));
3104 }
3105
3106 #[test]
3107 fn test_validate_ncname() {
3108 assert!(xsd_validate_datatype(
3109 &XsdDatatypeKind::NCName,
3110 "myElement",
3111 &[]
3112 ));
3113 assert!(xsd_validate_datatype(&XsdDatatypeKind::NCName, "_foo", &[]));
3114 assert!(!xsd_validate_datatype(
3115 &XsdDatatypeKind::NCName,
3116 "123abc",
3117 &[]
3118 ));
3119 assert!(!xsd_validate_datatype(&XsdDatatypeKind::NCName, "", &[]));
3120 }
3121
3122 #[test]
3123 fn test_validate_qname() {
3124 assert!(xsd_validate_datatype(
3125 &XsdDatatypeKind::QName,
3126 "ns:local",
3127 &[]
3128 ));
3129 assert!(xsd_validate_datatype(&XsdDatatypeKind::QName, "local", &[]));
3130 assert!(!xsd_validate_datatype(&XsdDatatypeKind::QName, "", &[]));
3131 }
3132
3133 #[test]
3134 fn test_validate_token() {
3135 assert!(xsd_validate_datatype(&XsdDatatypeKind::Token, "hello", &[]));
3136 assert!(!xsd_validate_datatype(
3137 &XsdDatatypeKind::Token,
3138 " hello",
3139 &[]
3140 ));
3141 assert!(!xsd_validate_datatype(
3142 &XsdDatatypeKind::Token,
3143 "hello ",
3144 &[]
3145 ));
3146 assert!(!xsd_validate_datatype(
3147 &XsdDatatypeKind::Token,
3148 "hello world",
3149 &[]
3150 ));
3151 assert!(!xsd_validate_datatype(
3152 &XsdDatatypeKind::Token,
3153 "hello\tworld",
3154 &[]
3155 ));
3156 }
3157
3158 #[test]
3159 fn test_validate_language() {
3160 assert!(xsd_validate_datatype(&XsdDatatypeKind::Language, "en", &[]));
3161 assert!(xsd_validate_datatype(
3162 &XsdDatatypeKind::Language,
3163 "en-US",
3164 &[]
3165 ));
3166 assert!(xsd_validate_datatype(
3167 &XsdDatatypeKind::Language,
3168 "zh-CN",
3169 &[]
3170 ));
3171 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Language, "", &[]));
3172 assert!(!xsd_validate_datatype(
3173 &XsdDatatypeKind::Language,
3174 "123",
3175 &[]
3176 ));
3177 }
3178
3179 #[test]
3180 fn test_validate_name() {
3181 assert!(xsd_validate_datatype(
3182 &XsdDatatypeKind::Name,
3183 "myElement",
3184 &[]
3185 ));
3186 assert!(xsd_validate_datatype(
3187 &XsdDatatypeKind::Name,
3188 "ns:local",
3189 &[]
3190 ));
3191 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Name, "", &[]));
3192 }
3193
3194 #[test]
3195 fn test_validate_nmtoken() {
3196 assert!(xsd_validate_datatype(
3197 &XsdDatatypeKind::Nmtoken,
3198 "token123",
3199 &[]
3200 ));
3201 assert!(xsd_validate_datatype(
3202 &XsdDatatypeKind::Nmtoken,
3203 "123token",
3204 &[]
3205 ));
3206 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Nmtoken, "", &[]));
3207 }
3208
3209 #[test]
3210 fn test_validate_duration() {
3211 assert!(xsd_validate_datatype(
3212 &XsdDatatypeKind::Duration,
3213 "P1Y2M3DT4H5M6S",
3214 &[]
3215 ));
3216 assert!(xsd_validate_datatype(
3217 &XsdDatatypeKind::Duration,
3218 "P1Y",
3219 &[]
3220 ));
3221 assert!(!xsd_validate_datatype(&XsdDatatypeKind::Duration, "", &[]));
3222 }
3223
3224 #[test]
3225 fn test_validate_g_year() {
3226 assert!(xsd_validate_datatype(&XsdDatatypeKind::GYear, "2023", &[]));
3227 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GYear, "", &[]));
3228 }
3229
3230 #[test]
3231 fn test_validate_g_month() {
3232 assert!(xsd_validate_datatype(&XsdDatatypeKind::GMonth, "--05", &[]));
3233 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GMonth, "", &[]));
3234 }
3235
3236 #[test]
3237 fn test_validate_g_day() {
3238 assert!(xsd_validate_datatype(&XsdDatatypeKind::GDay, "---15", &[]));
3239 assert!(!xsd_validate_datatype(&XsdDatatypeKind::GDay, "", &[]));
3240 }
3241
3242 #[test]
3245 fn test_facet_min_length() {
3246 let facets = vec![(XsdDatatypeKind::FacetMinLength, "3".to_string())];
3247 assert!(xsd_validate_datatype(
3248 &XsdDatatypeKind::String,
3249 "hello",
3250 &facets
3251 ));
3252 assert!(xsd_validate_datatype(
3253 &XsdDatatypeKind::String,
3254 "abc",
3255 &facets
3256 ));
3257 assert!(!xsd_validate_datatype(
3258 &XsdDatatypeKind::String,
3259 "ab",
3260 &facets
3261 ));
3262 }
3263
3264 #[test]
3265 fn test_facet_max_length() {
3266 let facets = vec![(XsdDatatypeKind::FacetMaxLength, "3".to_string())];
3267 assert!(xsd_validate_datatype(
3268 &XsdDatatypeKind::String,
3269 "ab",
3270 &facets
3271 ));
3272 assert!(xsd_validate_datatype(
3273 &XsdDatatypeKind::String,
3274 "abc",
3275 &facets
3276 ));
3277 assert!(!xsd_validate_datatype(
3278 &XsdDatatypeKind::String,
3279 "abcd",
3280 &facets
3281 ));
3282 }
3283
3284 #[test]
3285 fn test_facet_length() {
3286 let facets = vec![(XsdDatatypeKind::FacetLength, "3".to_string())];
3287 assert!(xsd_validate_datatype(
3288 &XsdDatatypeKind::String,
3289 "abc",
3290 &facets
3291 ));
3292 assert!(!xsd_validate_datatype(
3293 &XsdDatatypeKind::String,
3294 "ab",
3295 &facets
3296 ));
3297 assert!(!xsd_validate_datatype(
3298 &XsdDatatypeKind::String,
3299 "abcd",
3300 &facets
3301 ));
3302 }
3303
3304 #[test]
3305 fn test_facet_min_inclusive() {
3306 let facets = vec![(XsdDatatypeKind::FacetMinInclusive, "5".to_string())];
3307 assert!(xsd_validate_datatype(
3308 &XsdDatatypeKind::Integer,
3309 "5",
3310 &facets
3311 ));
3312 assert!(xsd_validate_datatype(
3313 &XsdDatatypeKind::Integer,
3314 "10",
3315 &facets
3316 ));
3317 assert!(!xsd_validate_datatype(
3318 &XsdDatatypeKind::Integer,
3319 "3",
3320 &facets
3321 ));
3322 }
3323
3324 #[test]
3325 fn test_facet_max_inclusive() {
3326 let facets = vec![(XsdDatatypeKind::FacetMaxInclusive, "10".to_string())];
3327 assert!(xsd_validate_datatype(
3328 &XsdDatatypeKind::Integer,
3329 "10",
3330 &facets
3331 ));
3332 assert!(xsd_validate_datatype(
3333 &XsdDatatypeKind::Integer,
3334 "5",
3335 &facets
3336 ));
3337 assert!(!xsd_validate_datatype(
3338 &XsdDatatypeKind::Integer,
3339 "15",
3340 &facets
3341 ));
3342 }
3343
3344 #[test]
3345 fn test_facet_pattern_digits() {
3346 let facets = vec![(XsdDatatypeKind::FacetPattern, r"\d+".to_string())];
3347 assert!(xsd_validate_datatype(
3348 &XsdDatatypeKind::String,
3349 "123",
3350 &facets
3351 ));
3352 assert!(!xsd_validate_datatype(
3353 &XsdDatatypeKind::String,
3354 "abc",
3355 &facets
3356 ));
3357 }
3358
3359 #[test]
3360 fn test_facet_pattern_alpha() {
3361 let facets = vec![(XsdDatatypeKind::FacetPattern, r"[a-zA-Z]+".to_string())];
3362 assert!(xsd_validate_datatype(
3363 &XsdDatatypeKind::String,
3364 "hello",
3365 &facets
3366 ));
3367 assert!(!xsd_validate_datatype(
3368 &XsdDatatypeKind::String,
3369 "123",
3370 &facets
3371 ));
3372 }
3373
3374 #[test]
3377 fn test_parse_empty_schema() {
3378 let schema_xml = r#"<?xml version="1.0"?>
3379 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3380 </xs:schema>"#;
3381
3382 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3383 assert!(schema.components.is_empty());
3384 }
3385
3386 #[test]
3387 fn test_parse_schema_with_target_namespace() {
3388 let schema_xml = r#"<?xml version="1.0"?>
3389 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
3390 targetNamespace="http://example.com/ns">
3391 </xs:schema>"#;
3392
3393 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3394 assert_eq!(
3395 schema.target_namespace,
3396 Some("http://example.com/ns".to_string())
3397 );
3398 }
3399
3400 #[test]
3401 fn test_parse_simple_element() {
3402 let schema_xml = r#"<?xml version="1.0"?>
3403 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3404 <xs:element name="name" type="xs:string"/>
3405 </xs:schema>"#;
3406
3407 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3408 assert_eq!(schema.components.len(), 1);
3409 assert_eq!(
3410 schema.components[0].component_type,
3411 XsdComponentType::Element
3412 );
3413 assert_eq!(schema.components[0].name, Some("name".to_string()));
3414 assert_eq!(schema.components[0].datatype, Some(XsdDatatypeKind::String));
3415 }
3416
3417 #[test]
3418 fn test_parse_integer_element() {
3419 let schema_xml = r#"<?xml version="1.0"?>
3420 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3421 <xs:element name="age" type="xs:integer"/>
3422 </xs:schema>"#;
3423
3424 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3425 assert_eq!(schema.components.len(), 1);
3426 assert_eq!(schema.components[0].name, Some("age".to_string()));
3427 assert_eq!(
3428 schema.components[0].datatype,
3429 Some(XsdDatatypeKind::Integer)
3430 );
3431 }
3432
3433 #[test]
3434 fn test_parse_element_with_attributes() {
3435 let schema_xml = r#"<?xml version="1.0"?>
3436 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3437 <xs:element name="product">
3438 <xs:complexType>
3439 <xs:sequence>
3440 <xs:element name="name" type="xs:string"/>
3441 <xs:element name="price" type="xs:decimal"/>
3442 </xs:sequence>
3443 <xs:attribute name="id" type="xs:integer" use="required"/>
3444 </xs:complexType>
3445 </xs:element>
3446 </xs:schema>"#;
3447
3448 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3449 assert_eq!(schema.components.len(), 1);
3450 assert_eq!(schema.components[0].name, Some("product".to_string()));
3451
3452 let ct = &schema.components[0].children;
3454 let complex_type = ct
3455 .iter()
3456 .find(|c| c.component_type == XsdComponentType::ComplexType);
3457 assert!(complex_type.is_some());
3458 if let Some(ctc) = complex_type {
3459 assert_eq!(ctc.attributes.len(), 1);
3460 assert_eq!(ctc.attributes[0].name, Some("id".to_string()));
3461 assert_eq!(ctc.attributes[0].datatype, Some(XsdDatatypeKind::Integer));
3462 }
3463 }
3464
3465 #[test]
3466 fn test_parse_complex_type_with_sequence() {
3467 let schema_xml = r#"<?xml version="1.0"?>
3468 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3469 <xs:complexType name="AddressType">
3470 <xs:sequence>
3471 <xs:element name="street" type="xs:string"/>
3472 <xs:element name="city" type="xs:string"/>
3473 <xs:element name="zip" type="xs:string"/>
3474 </xs:sequence>
3475 </xs:complexType>
3476 </xs:schema>"#;
3477
3478 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3479 assert_eq!(schema.components.len(), 1);
3480 assert_eq!(
3481 schema.components[0].component_type,
3482 XsdComponentType::ComplexType
3483 );
3484 assert_eq!(schema.components[0].name, Some("AddressType".to_string()));
3485 }
3486
3487 #[test]
3488 fn test_parse_restriction() {
3489 let schema_xml = r#"<?xml version="1.0"?>
3490 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3491 <xs:simpleType name="AgeType">
3492 <xs:restriction base="xs:integer">
3493 <xs:minInclusive value="0"/>
3494 <xs:maxInclusive value="150"/>
3495 </xs:restriction>
3496 </xs:simpleType>
3497 </xs:schema>"#;
3498
3499 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3500 assert_eq!(schema.components.len(), 1);
3501 assert_eq!(
3502 schema.components[0].component_type,
3503 XsdComponentType::SimpleType
3504 );
3505
3506 let st = &schema.components[0];
3508 assert_eq!(st.datatype, Some(XsdDatatypeKind::Integer));
3509 assert!(!st.facets.is_empty());
3510 }
3511
3512 #[test]
3513 fn test_parse_enumeration() {
3514 let schema_xml = r#"<?xml version="1.0"?>
3515 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3516 <xs:simpleType name="ColorType">
3517 <xs:restriction base="xs:string">
3518 <xs:enumeration value="red"/>
3519 <xs:enumeration value="green"/>
3520 <xs:enumeration value="blue"/>
3521 </xs:restriction>
3522 </xs:simpleType>
3523 </xs:schema>"#;
3524
3525 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3526 assert_eq!(schema.components.len(), 1);
3527 assert_eq!(schema.components[0].name, Some("ColorType".to_string()));
3528 }
3529
3530 #[test]
3531 fn test_parse_min_max_occurs() {
3532 let schema_xml = r#"<?xml version="1.0"?>
3533 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3534 <xs:element name="items">
3535 <xs:complexType>
3536 <xs:sequence>
3537 <xs:element name="item" type="xs:string"
3538 minOccurs="0" maxOccurs="unbounded"/>
3539 </xs:sequence>
3540 </xs:complexType>
3541 </xs:element>
3542 </xs:schema>"#;
3543
3544 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3545 assert_eq!(schema.components.len(), 1);
3546
3547 let elem = &schema.components[0];
3549 let ct = elem
3550 .children
3551 .iter()
3552 .find(|c| c.component_type == XsdComponentType::ComplexType);
3553 assert!(ct.is_some());
3554 if let Some(ctc) = ct {
3555 let seq = ctc
3556 .children
3557 .iter()
3558 .find(|c| c.component_type == XsdComponentType::Sequence);
3559 assert!(seq.is_some());
3560 if let Some(seqc) = seq {
3561 assert!(!seqc.children.is_empty());
3562 let item = &seqc.children[0];
3563 assert_eq!(item.min_occurs, 0);
3564 assert_eq!(item.max_occurs, -1);
3565 }
3566 }
3567 }
3568
3569 #[test]
3570 fn test_parse_attribute_default() {
3571 let schema_xml = r#"<?xml version="1.0"?>
3572 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3573 <xs:element name="book">
3574 <xs:complexType>
3575 <xs:sequence>
3576 <xs:element name="title" type="xs:string"/>
3577 </xs:sequence>
3578 <xs:attribute name="lang" type="xs:string" default="en"/>
3579 <xs:attribute name="id" type="xs:integer" use="required"/>
3580 </xs:complexType>
3581 </xs:element>
3582 </xs:schema>"#;
3583
3584 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3585 let elem = &schema.components[0];
3586 let ct = elem
3587 .children
3588 .iter()
3589 .find(|c| c.component_type == XsdComponentType::ComplexType);
3590 assert!(ct.is_some());
3591 if let Some(ctc) = ct {
3592 let lang_attr = ctc
3593 .attributes
3594 .iter()
3595 .find(|a| a.name.as_deref() == Some("lang"));
3596 assert!(lang_attr.is_some());
3597 if let Some(la) = lang_attr {
3598 assert_eq!(la.min_occurs, 0); }
3600
3601 let id_attr = ctc
3602 .attributes
3603 .iter()
3604 .find(|a| a.name.as_deref() == Some("id"));
3605 assert!(id_attr.is_some());
3606 }
3607 }
3608
3609 #[test]
3610 fn test_parse_element_with_ref() {
3611 let schema_xml = r#"<?xml version="1.0"?>
3612 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3613 <xs:element name="root">
3614 <xs:complexType>
3615 <xs:sequence>
3616 <xs:element ref="child" minOccurs="0"/>
3617 </xs:sequence>
3618 </xs:complexType>
3619 </xs:element>
3620 <xs:element name="child" type="xs:string"/>
3621 </xs:schema>"#;
3622
3623 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3624 assert_eq!(schema.components.len(), 2);
3625 let root = &schema.components[0];
3627 let ct = root
3628 .children
3629 .iter()
3630 .find(|c| c.component_type == XsdComponentType::ComplexType);
3631 assert!(ct.is_some());
3632 if let Some(ctc) = ct {
3633 let seq = ctc
3634 .children
3635 .iter()
3636 .find(|c| c.component_type == XsdComponentType::Sequence);
3637 assert!(seq.is_some());
3638 if let Some(seqc) = seq {
3639 assert!(!seqc.children.is_empty());
3640 let ref_elem = &seqc.children[0];
3641 assert_eq!(ref_elem.ref_name, Some("child".to_string()));
3642 }
3643 }
3644 }
3645
3646 #[test]
3649 fn test_validate_simple_element() {
3650 let schema_xml = r#"<?xml version="1.0"?>
3651 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3652 <xs:element name="name" type="xs:string"/>
3653 </xs:schema>"#;
3654
3655 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3656
3657 let doc = r#"<?xml version="1.0"?>
3658 <name>John Doe</name>"#;
3659
3660 assert!(xsd_validate(&schema, doc).is_ok());
3661 }
3662
3663 #[test]
3664 fn test_validate_integer_element() {
3665 let schema_xml = r#"<?xml version="1.0"?>
3666 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3667 <xs:element name="age" type="xs:integer"/>
3668 </xs:schema>"#;
3669
3670 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3671
3672 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3673 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>not-a-number</age>"#).is_err());
3674 }
3675
3676 #[test]
3677 fn test_validate_complex_element() {
3678 let schema_xml = r#"<?xml version="1.0"?>
3679 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3680 <xs:element name="product">
3681 <xs:complexType>
3682 <xs:sequence>
3683 <xs:element name="name" type="xs:string"/>
3684 <xs:element name="price" type="xs:decimal"/>
3685 </xs:sequence>
3686 <xs:attribute name="id" type="xs:integer" use="required"/>
3687 </xs:complexType>
3688 </xs:element>
3689 </xs:schema>"#;
3690
3691 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3692
3693 let valid_doc = r#"<?xml version="1.0"?>
3694 <product id="123">
3695 <name>Widget</name>
3696 <price>9.99</price>
3697 </product>"#;
3698
3699 assert!(xsd_validate(&schema, valid_doc).is_ok());
3700 }
3701
3702 #[test]
3703 fn test_validate_missing_required_attribute() {
3704 let schema_xml = r#"<?xml version="1.0"?>
3705 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3706 <xs:element name="product">
3707 <xs:complexType>
3708 <xs:sequence>
3709 <xs:element name="name" type="xs:string"/>
3710 </xs:sequence>
3711 <xs:attribute name="id" type="xs:integer" use="required"/>
3712 </xs:complexType>
3713 </xs:element>
3714 </xs:schema>"#;
3715
3716 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3717
3718 let invalid_doc = r#"<?xml version="1.0"?>
3719 <product>
3720 <name>Widget</name>
3721 </product>"#;
3722
3723 assert!(xsd_validate(&schema, invalid_doc).is_err());
3724 }
3725
3726 #[test]
3727 fn test_validate_enumeration_facet() {
3728 let schema_xml = r#"<?xml version="1.0"?>
3729 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3730 <xs:element name="color">
3731 <xs:simpleType>
3732 <xs:restriction base="xs:string">
3733 <xs:enumeration value="red"/>
3734 <xs:enumeration value="green"/>
3735 <xs:enumeration value="blue"/>
3736 </xs:restriction>
3737 </xs:simpleType>
3738 </xs:element>
3739 </xs:schema>"#;
3740
3741 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3742
3743 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><color>red</color>"#).is_ok());
3746 }
3747
3748 #[test]
3749 fn test_validate_boolean_element() {
3750 let schema_xml = r#"<?xml version="1.0"?>
3751 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3752 <xs:element name="active" type="xs:boolean"/>
3753 </xs:schema>"#;
3754
3755 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3756
3757 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>true</active>"#).is_ok());
3758 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>false</active>"#).is_ok());
3759 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>1</active>"#).is_ok());
3760 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><active>yes</active>"#).is_err());
3761 }
3762
3763 #[test]
3764 fn test_validate_element_with_range_constraint() {
3765 let schema_xml = r#"<?xml version="1.0"?>
3766 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3767 <xs:element name="age">
3768 <xs:simpleType>
3769 <xs:restriction base="xs:integer">
3770 <xs:minInclusive value="0"/>
3771 <xs:maxInclusive value="150"/>
3772 </xs:restriction>
3773 </xs:simpleType>
3774 </xs:element>
3775 </xs:schema>"#;
3776
3777 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3778
3779 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>25</age>"#).is_ok());
3780 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>0</age>"#).is_ok());
3781 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><age>150</age>"#).is_ok());
3782 }
3784
3785 #[test]
3786 fn test_validate_optional_element() {
3787 let schema_xml = r#"<?xml version="1.0"?>
3788 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3789 <xs:element name="person">
3790 <xs:complexType>
3791 <xs:sequence>
3792 <xs:element name="name" type="xs:string"/>
3793 <xs:element name="nickname" type="xs:string" minOccurs="0"/>
3794 </xs:sequence>
3795 </xs:complexType>
3796 </xs:element>
3797 </xs:schema>"#;
3798
3799 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3800
3801 let doc_with_nick = r#"<?xml version="1.0"?>
3802 <person>
3803 <name>John</name>
3804 <nickname>Johnny</nickname>
3805 </person>"#;
3806
3807 let doc_without_nick = r#"<?xml version="1.0"?>
3808 <person>
3809 <name>John</name>
3810 </person>"#;
3811
3812 assert!(xsd_validate(&schema, doc_with_nick).is_ok());
3813 assert!(xsd_validate(&schema, doc_without_nick).is_ok());
3814 }
3815
3816 #[test]
3817 fn test_validate_unbounded_element() {
3818 let schema_xml = r#"<?xml version="1.0"?>
3819 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3820 <xs:element name="items">
3821 <xs:complexType>
3822 <xs:sequence>
3823 <xs:element name="item" type="xs:string"
3824 minOccurs="0" maxOccurs="unbounded"/>
3825 </xs:sequence>
3826 </xs:complexType>
3827 </xs:element>
3828 </xs:schema>"#;
3829
3830 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3831
3832 let doc = r#"<?xml version="1.0"?>
3833 <items>
3834 <item>one</item>
3835 <item>two</item>
3836 <item>three</item>
3837 </items>"#;
3838
3839 assert!(xsd_validate(&schema, doc).is_ok());
3840 }
3841
3842 #[test]
3843 fn test_validate_date_element() {
3844 let schema_xml = r#"<?xml version="1.0"?>
3845 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3846 <xs:element name="birthDate" type="xs:date"/>
3847 </xs:schema>"#;
3848
3849 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3850
3851 assert!(xsd_validate(
3852 &schema,
3853 r#"<?xml version="1.0"?><birthDate>1990-01-15</birthDate>"#
3854 )
3855 .is_ok());
3856 assert!(xsd_validate(
3857 &schema,
3858 r#"<?xml version="1.0"?><birthDate>not-a-date</birthDate>"#
3859 )
3860 .is_err());
3861 }
3862
3863 #[test]
3864 fn test_validate_choice() {
3865 let schema_xml = r#"<?xml version="1.0"?>
3866 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3867 <xs:element name="contact">
3868 <xs:complexType>
3869 <xs:choice>
3870 <xs:element name="email" type="xs:string"/>
3871 <xs:element name="phone" type="xs:string"/>
3872 </xs:choice>
3873 </xs:complexType>
3874 </xs:element>
3875 </xs:schema>"#;
3876
3877 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3878
3879 assert!(xsd_validate(
3880 &schema,
3881 r#"<?xml version="1.0"?><contact><email>a@b.com</email></contact>"#
3882 )
3883 .is_ok());
3884 assert!(xsd_validate(
3885 &schema,
3886 r#"<?xml version="1.0"?><contact><phone>555-1234</phone></contact>"#
3887 )
3888 .is_ok());
3889 }
3890
3891 #[test]
3892 fn test_validate_positive_integer_constraint() {
3893 let schema_xml = r#"<?xml version="1.0"?>
3894 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3895 <xs:element name="quantity" type="xs:positiveInteger"/>
3896 </xs:schema>"#;
3897
3898 let schema = xsd_parse(schema_xml).expect("Failed to parse schema");
3899
3900 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>1</quantity>"#).is_ok());
3901 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>0</quantity>"#).is_err());
3902 assert!(xsd_validate(&schema, r#"<?xml version="1.0"?><quantity>-1</quantity>"#).is_err());
3903 }
3904
3905 #[test]
3908 fn test_xml_schema_new_mem_parser_ctxt() {
3909 let schema_xml = r#"<?xml version="1.0"?>
3910 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3911 <xs:element name="name" type="xs:string"/>
3912 </xs:schema>"#;
3913
3914 let ctxt = unsafe {
3915 xmlSchemaNewMemParserCtxt(
3916 schema_xml.as_ptr() as *const c_char,
3917 schema_xml.len() as c_int,
3918 )
3919 };
3920 assert!(!ctxt.is_null());
3921
3922 let schema = unsafe { xmlSchemaParse(ctxt) };
3923 assert!(!schema.is_null());
3924
3925 unsafe {
3926 xmlSchemaFree(schema);
3927 }
3928 }
3929
3930 #[test]
3931 fn test_xml_schema_validate_doc() {
3932 let schema_xml = r#"<?xml version="1.0"?>
3933 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3934 <xs:element name="name" type="xs:string"/>
3935 </xs:schema>"#;
3936
3937 let doc_xml = r#"<?xml version="1.0"?>
3938 <name>John Doe</name>"#;
3939
3940 let ctxt = unsafe {
3941 xmlSchemaNewMemParserCtxt(
3942 schema_xml.as_ptr() as *const c_char,
3943 schema_xml.len() as c_int,
3944 )
3945 };
3946 let schema = unsafe { xmlSchemaParse(ctxt) };
3947 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
3948
3949 let doc = unsafe {
3950 crate::abi::exports_xml2::xmlReadMemory(
3951 doc_xml.as_ptr() as *const c_char,
3952 doc_xml.len() as c_int,
3953 c"test.xml".as_ptr() as *const c_char,
3954 ptr::null(),
3955 0,
3956 )
3957 };
3958
3959 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
3960 assert_eq!(result, 0);
3961
3962 unsafe {
3963 xmlSchemaFreeValidCtxt(valid_ctxt);
3964 xmlSchemaFree(schema);
3965 crate::abi::exports_xml2::xmlFreeDoc(doc);
3966 }
3967 }
3968
3969 #[test]
3970 fn test_xml_schema_validate_invalid_doc() {
3971 let schema_xml = r#"<?xml version="1.0"?>
3972 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3973 <xs:element name="age" type="xs:integer"/>
3974 </xs:schema>"#;
3975
3976 let doc_xml = r#"<?xml version="1.0"?>
3977 <age>not-a-number</age>"#;
3978
3979 let ctxt = unsafe {
3980 xmlSchemaNewMemParserCtxt(
3981 schema_xml.as_ptr() as *const c_char,
3982 schema_xml.len() as c_int,
3983 )
3984 };
3985 let schema = unsafe { xmlSchemaParse(ctxt) };
3986 let valid_ctxt = unsafe { xmlSchemaNewValidCtxt(schema) };
3987
3988 let doc = unsafe {
3989 crate::abi::exports_xml2::xmlReadMemory(
3990 doc_xml.as_ptr() as *const c_char,
3991 doc_xml.len() as c_int,
3992 c"test.xml".as_ptr() as *const c_char,
3993 ptr::null(),
3994 0,
3995 )
3996 };
3997
3998 let result = unsafe { xmlSchemaValidateDoc(valid_ctxt, doc) };
3999 assert_ne!(result, 0); unsafe {
4002 xmlSchemaFreeValidCtxt(valid_ctxt);
4003 xmlSchemaFree(schema);
4004 crate::abi::exports_xml2::xmlFreeDoc(doc);
4005 }
4006 }
4007
4008 #[test]
4009 fn test_xml_schema_new_valid_ctxt_null() {
4010 let ctxt = unsafe { xmlSchemaNewValidCtxt(ptr::null_mut()) };
4011 assert!(!ctxt.is_null());
4012 unsafe { xmlSchemaFreeValidCtxt(ctxt) };
4013 }
4014
4015 #[test]
4016 fn test_xml_schema_free_null() {
4017 unsafe {
4018 xmlSchemaFree(ptr::null_mut());
4019 xmlSchemaFreeParserCtxt(ptr::null_mut());
4020 xmlSchemaFreeValidCtxt(ptr::null_mut());
4021 }
4022 }
4023
4024 #[test]
4025 fn test_xml_schema_new_parser_ctxt_null() {
4026 let ctxt = unsafe { xmlSchemaNewParserCtxt(ptr::null()) };
4027 assert!(!ctxt.is_null());
4028 unsafe {
4030 allocator::xmlFreeImpl(ctxt);
4031 }
4032 }
4033
4034 #[test]
4035 fn test_datatype_parse_kind() {
4036 assert_eq!(
4037 parse_datatype_kind("xs:string"),
4038 Some(XsdDatatypeKind::String)
4039 );
4040 assert_eq!(parse_datatype_kind("string"), Some(XsdDatatypeKind::String));
4041 assert_eq!(
4042 parse_datatype_kind("xs:integer"),
4043 Some(XsdDatatypeKind::Integer)
4044 );
4045 assert_eq!(
4046 parse_datatype_kind("xs:boolean"),
4047 Some(XsdDatatypeKind::Boolean)
4048 );
4049 assert_eq!(
4050 parse_datatype_kind("xs:decimal"),
4051 Some(XsdDatatypeKind::Decimal)
4052 );
4053 assert_eq!(
4054 parse_datatype_kind("xs:float"),
4055 Some(XsdDatatypeKind::Float)
4056 );
4057 assert_eq!(
4058 parse_datatype_kind("xs:double"),
4059 Some(XsdDatatypeKind::Double)
4060 );
4061 assert_eq!(parse_datatype_kind("xs:date"), Some(XsdDatatypeKind::Date));
4062 assert_eq!(
4063 parse_datatype_kind("xs:dateTime"),
4064 Some(XsdDatatypeKind::DateTime)
4065 );
4066 assert_eq!(parse_datatype_kind("xs:time"), Some(XsdDatatypeKind::Time));
4067 assert_eq!(
4068 parse_datatype_kind("xs:hexBinary"),
4069 Some(XsdDatatypeKind::HexBinary)
4070 );
4071 assert_eq!(
4072 parse_datatype_kind("xs:base64Binary"),
4073 Some(XsdDatatypeKind::Base64Binary)
4074 );
4075 assert_eq!(
4076 parse_datatype_kind("xs:anyURI"),
4077 Some(XsdDatatypeKind::AnyURI)
4078 );
4079 assert_eq!(
4080 parse_datatype_kind("xs:QName"),
4081 Some(XsdDatatypeKind::QName)
4082 );
4083 assert_eq!(
4084 parse_datatype_kind("xs:normalizedString"),
4085 Some(XsdDatatypeKind::NormalizedString)
4086 );
4087 assert_eq!(
4088 parse_datatype_kind("xs:token"),
4089 Some(XsdDatatypeKind::Token)
4090 );
4091 assert_eq!(
4092 parse_datatype_kind("xs:language"),
4093 Some(XsdDatatypeKind::Language)
4094 );
4095 assert_eq!(parse_datatype_kind("xs:Name"), Some(XsdDatatypeKind::Name));
4096 assert_eq!(
4097 parse_datatype_kind("xs:NCName"),
4098 Some(XsdDatatypeKind::NCName)
4099 );
4100 assert_eq!(parse_datatype_kind("xs:ID"), Some(XsdDatatypeKind::Id));
4101 assert_eq!(
4102 parse_datatype_kind("xs:IDREF"),
4103 Some(XsdDatatypeKind::Idref)
4104 );
4105 assert_eq!(
4106 parse_datatype_kind("xs:integer"),
4107 Some(XsdDatatypeKind::Integer)
4108 );
4109 assert_eq!(parse_datatype_kind("xs:long"), Some(XsdDatatypeKind::Long));
4110 assert_eq!(parse_datatype_kind("xs:int"), Some(XsdDatatypeKind::Int));
4111 assert_eq!(
4112 parse_datatype_kind("xs:short"),
4113 Some(XsdDatatypeKind::Short)
4114 );
4115 assert_eq!(parse_datatype_kind("xs:byte"), Some(XsdDatatypeKind::Byte));
4116 assert_eq!(
4117 parse_datatype_kind("xs:positiveInteger"),
4118 Some(XsdDatatypeKind::PositiveInteger)
4119 );
4120 assert_eq!(
4121 parse_datatype_kind("xs:negativeInteger"),
4122 Some(XsdDatatypeKind::NegativeInteger)
4123 );
4124 assert_eq!(parse_datatype_kind("unknown"), None);
4125 }
4126}