xee_xpath_load/
load.rs

1use anyhow::Result;
2use std::{
3    fs::File,
4    io::{BufReader, Read},
5    path::Path,
6};
7
8use xee_xpath_compiler::sequence::Item;
9
10use xee_xpath::{context::StaticContextBuilder, error::Result as XPathResult};
11use xee_xpath::{DocumentHandle, Documents, Queries, Query};
12
13pub fn convert_string(_: &mut Documents, item: &Item) -> XPathResult<String> {
14    Ok(item.to_atomic()?.try_into()?)
15}
16
17pub fn convert_boolean(documents: &mut Documents, item: &Item) -> XPathResult<bool> {
18    Ok(convert_string(documents, item)? == "true")
19}
20
21pub trait ContextLoadable<C: ?Sized>: Sized {
22    fn static_context_builder(context: &C) -> StaticContextBuilder;
23
24    fn load_with_context(queries: &Queries, context: &C) -> Result<impl Query<Self>>;
25
26    fn load_from_xml_with_context(xml: &str, context: &C) -> Result<Self> {
27        let mut documents = Documents::new();
28        // TODO: default document URI is just hardcoded
29        let document_id = documents.add_string("http://example.com".try_into().unwrap(), xml)?;
30
31        Self::load_from_node_with_context(documents, document_id, context)
32    }
33
34    fn load_from_node_with_context(
35        mut documents: Documents,
36        document_id: DocumentHandle,
37        context: &C,
38    ) -> Result<Self> {
39        let static_context_builder = Self::static_context_builder(context);
40        let queries = Queries::new(static_context_builder);
41
42        let query = Self::load_with_context(&queries, context)?;
43        let root = documents.document_node(document_id).unwrap();
44        // the test runner needs to work from the document element
45        let document_element = documents.xot().document_element(root).unwrap();
46        Ok(query.execute(&mut documents, document_element)?)
47    }
48}
49
50pub trait Loadable: Sized {
51    fn static_context_builder<'namespaces>() -> StaticContextBuilder<'namespaces>;
52
53    fn load(queries: &Queries) -> Result<impl Query<Self>>;
54
55    fn load_from_xml(xml: &str) -> Result<Self> {
56        Self::load_from_xml_with_context(xml, &())
57    }
58
59    fn load_from_node(documents: Documents, document_id: DocumentHandle) -> Result<Self> {
60        Self::load_from_node_with_context(documents, document_id, &())
61    }
62}
63
64impl<T: Loadable> ContextLoadable<()> for T {
65    fn static_context_builder(_context: &()) -> StaticContextBuilder {
66        T::static_context_builder()
67    }
68
69    fn load_with_context(queries: &Queries, _context: &()) -> Result<impl Query<Self>> {
70        Self::load(queries)
71    }
72}
73
74pub trait ContextWithPath {
75    fn path(&self) -> &Path;
76}
77
78pub trait PathLoadable<C: ContextWithPath>: ContextLoadable<C> {
79    fn load_from_file(context: &C) -> Result<Self> {
80        let path = context.path();
81        let xml_file = File::open(path)?;
82        let mut buf_reader = BufReader::new(xml_file);
83        let mut xml = String::new();
84        buf_reader.read_to_string(&mut xml)?;
85        Self::load_from_xml_with_context(&xml, context)
86    }
87}
88
89impl<C: ContextWithPath, T: ContextLoadable<C>> PathLoadable<C> for T {}