use relax_ng::{
Content, DatatypeRegistry, Element, ExpandedName, ResolveError, Schema, SchemaResolver,
SchemaSource, SchemaSyntax,
};
use std::collections::BTreeMap;
struct InMemoryResolver {
sources: BTreeMap<&'static str, &'static str>,
}
impl SchemaResolver for InMemoryResolver {
fn resolve(&self, href: &str, _base_uri: &str) -> Result<SchemaSource, ResolveError> {
let text = self
.sources
.get(href)
.ok_or_else(|| ResolveError::new(format!("no such resource: {href}")))?;
Ok(SchemaSource::new(*text, href, SchemaSyntax::Compact))
}
}
#[derive(Clone)]
struct Doc {
name: &'static str,
attributes: Vec<(&'static str, &'static str)>,
children: Vec<Doc>,
text: Option<&'static str>,
}
impl Doc {
fn new(name: &'static str) -> Self {
Self {
name,
attributes: Vec::new(),
children: Vec::new(),
text: None,
}
}
fn attr(mut self, name: &'static str, value: &'static str) -> Self {
self.attributes.push((name, value));
self
}
fn text(mut self, text: &'static str) -> Self {
self.text = Some(text);
self
}
fn child(mut self, child: Doc) -> Self {
self.children.push(child);
self
}
}
impl Element for Doc {
type Location = String;
fn name(&self) -> ExpandedName {
ExpandedName::new(None::<String>, self.name)
}
fn attributes(&self) -> impl Iterator<Item = (ExpandedName, String)> {
self.attributes.iter().map(|(name, value)| {
(
ExpandedName::new(None::<String>, *name),
(*value).to_owned(),
)
})
}
fn children(&self) -> impl Iterator<Item = Content<Self>> {
self.children
.iter()
.cloned()
.map(Content::Element)
.chain(self.text.map(|text| Content::Text(text.to_owned())))
}
}
fn main() {
let resolver = InMemoryResolver {
sources: BTreeMap::new(),
};
let source = SchemaSource::new(
r#"element note {
attribute author { text },
element body { text }
}"#,
"memory:/note.rnc",
SchemaSyntax::Compact,
);
let schema = Schema::compile(&source, &resolver).expect("schema compiles");
let registry = DatatypeRegistry::new();
let valid = Doc::new("note")
.attr("author", "jane")
.child(Doc::new("body").text("Remember the milk."));
let errors = schema
.validate(®istry, &valid)
.expect("known datatypes only");
println!("valid document: {} problem(s)", errors.len());
assert!(errors.is_empty());
let invalid = Doc::new("note").child(Doc::new("body").text("Missing the author attribute."));
let errors = schema
.validate(®istry, &invalid)
.expect("known datatypes only");
println!("invalid document: {} problem(s)", errors.len());
for error in &errors {
println!(" - {error}");
}
assert!(!errors.is_empty());
}