libxml/schemas/
validation.rs

1//!
2//! Wrapping of the Validation Context (xmlSchemaValidCtxt)
3//!
4use super::common;
5
6use super::Schema;
7use super::SchemaParserContext;
8
9use crate::bindings;
10
11use crate::tree::document::Document;
12use crate::tree::node::Node;
13
14use crate::error::StructuredError;
15
16use std::ffi::CString;
17use std::os::raw::c_char;
18
19/// Wrapper on xmlSchemaValidCtxt
20pub struct SchemaValidationContext {
21  ctxt: *mut bindings::_xmlSchemaValidCtxt,
22  errlog: *mut Vec<StructuredError>,
23  _schema: Schema,
24}
25
26
27impl SchemaValidationContext {
28  /// Create a schema validation context from a parser object
29  pub fn from_parser(parser: &mut SchemaParserContext) -> Result<Self, Vec<StructuredError>> {
30    let schema = Schema::from_parser(parser);
31
32    match schema {
33      Ok(s) => {
34        let ctx = unsafe { bindings::xmlSchemaNewValidCtxt(s.as_ptr()) };
35
36        if ctx.is_null() {
37          panic!("Failed to create validation context from XML schema") // TODO error handling
38        }
39
40        Ok(Self::from_raw(ctx, s))
41      }
42      Err(e) => Err(e),
43    }
44  }
45
46  /// Validates a given Document, that is to be tested to comply with the loaded XSD schema definition
47  pub fn validate_document(&mut self, doc: &Document) -> Result<(), Vec<StructuredError>> {
48    let rc = unsafe { bindings::xmlSchemaValidateDoc(self.ctxt, doc.doc_ptr()) };
49
50    match rc {
51      -1 => panic!("Failed to validate document due to internal error"), // TODO error handling
52      0 => Ok(()),
53      _ => Err(self.drain_errors()),
54    }
55  }
56
57  /// Validates a given file from path for its compliance with the loaded XSD schema definition
58  pub fn validate_file(&mut self, path: &str) -> Result<(), Vec<StructuredError>> {
59    let path = CString::new(path).unwrap(); // TODO error handling for \0 containing strings
60    let path_ptr = path.as_bytes_with_nul().as_ptr() as *const c_char;
61
62    let rc = unsafe { bindings::xmlSchemaValidateFile(self.ctxt, path_ptr, 0) };
63
64    match rc {
65      -1 => panic!("Failed to validate file due to internal error"), // TODO error handling
66      0 => Ok(()),
67      _ => Err(self.drain_errors()),
68    }
69  }
70
71  /// Validates a branch or leaf of a document given as a Node against the loaded XSD schema definition
72  pub fn validate_node(&mut self, node: &Node) -> Result<(), Vec<StructuredError>> {
73    let rc = unsafe { bindings::xmlSchemaValidateOneElement(self.ctxt, node.node_ptr()) };
74
75    match rc {
76      -1 => panic!("Failed to validate element due to internal error"), // TODO error handling
77      0 => Ok(()),
78      _ => Err(self.drain_errors()),
79    }
80  }
81
82  /// Drains error log from errors that might have accumulated while validating something
83  pub fn drain_errors(&mut self) -> Vec<StructuredError> {
84    assert!(!self.errlog.is_null());
85    let errors = unsafe { &mut *self.errlog };
86    std::mem::take(errors)
87  }
88
89  /// Return a raw pointer to the underlying xmlSchemaValidCtxt structure
90  pub fn as_ptr(&self) -> *mut bindings::_xmlSchemaValidCtxt {
91    self.ctxt
92  }
93}
94
95/// Private Interface
96impl SchemaValidationContext {
97  fn from_raw(ctx: *mut bindings::_xmlSchemaValidCtxt, schema: Schema) -> Self {
98    let errors: Box<Vec<StructuredError>> = Box::default();
99
100    unsafe {
101      let reference: *mut Vec<StructuredError> = std::mem::transmute(errors);
102      bindings::xmlSchemaSetValidStructuredErrors(
103        ctx,
104        Some(common::structured_error_handler),
105        reference as *mut _,
106        // Box::into_raw(Box::new(Rc::downgrade(&errors))) as *mut _,
107      );
108      Self {
109        ctxt: ctx,
110        errlog: reference,
111        _schema: schema,
112      }
113    }
114  }
115}
116
117impl Drop for SchemaValidationContext {
118  fn drop(&mut self) {
119    unsafe {
120      bindings::xmlSchemaFreeValidCtxt(self.ctxt);
121      if !self.errlog.is_null() {
122        let errors: Box<Vec<StructuredError>> = std::mem::transmute(self.errlog);
123        drop(errors)
124      }
125    }
126  }
127}