xml_schema_derive/xsd/
mod.rs

1mod annotation;
2mod attribute;
3mod attribute_group;
4mod complex_content;
5mod complex_type;
6mod element;
7mod extension;
8mod import;
9mod list;
10mod max_occurences;
11mod qualification;
12mod restriction;
13mod rust_types_mapping;
14mod schema;
15mod sequence;
16mod simple_content;
17mod simple_type;
18mod union;
19mod xsd_context;
20
21use heck::ToSnakeCase;
22use proc_macro2::{Ident, TokenStream};
23use std::collections::BTreeMap;
24use std::fs;
25use syn::Visibility;
26use xsd_context::XsdContext;
27use yaserde::de::from_str;
28
29trait Implementation {
30  fn implement(
31    &self,
32    _namespace_definition: &TokenStream,
33    _prefix: &Option<String>,
34    _context: &XsdContext,
35  ) -> TokenStream {
36    unimplemented!()
37  }
38
39  fn implement_childs(
40    &self,
41    _namespace_definition: &TokenStream,
42    _prefix: &Option<String>,
43    _context: &XsdContext,
44    _struct_name: &Ident,
45  ) -> TokenStream {
46    unimplemented!()
47  }
48}
49
50#[derive(Clone, Debug)]
51pub struct Xsd {
52  name: String,
53  vis: Visibility,
54  context: XsdContext,
55  schema: schema::Schema,
56}
57
58impl Xsd {
59  pub fn new(
60    name: String,
61    vis: Visibility,
62    content: &str,
63    module_namespace_mappings: &BTreeMap<String, String>,
64  ) -> Result<Self, String> {
65    let context = XsdContext::new(content)?;
66    let context = context.with_module_namespace_mappings(module_namespace_mappings);
67    let schema: schema::Schema = from_str(content)?;
68
69    Ok(Xsd {
70      name,
71      vis,
72      context,
73      schema,
74    })
75  }
76
77  pub fn new_from_file(
78    name: String,
79    vis: Visibility,
80    source: &str,
81    module_namespace_mappings: &BTreeMap<String, String>,
82  ) -> Result<Self, String> {
83    let content = if source.starts_with("http://") || source.starts_with("https://") {
84      log::info!("Load HTTP schema {}", source);
85      reqwest::blocking::get(source)
86        .map_err(|e| e.to_string())?
87        .text()
88        .map_err(|e| e.to_string())?
89    } else {
90      let path = std::env::current_dir().unwrap();
91      log::info!("The current directory is {}", path.display());
92
93      fs::read_to_string(source).map_err(|e| e.to_string())?
94    };
95
96    // skip BOM header, can be present on some files
97    let content = if content.as_bytes()[0..3] == [0xef, 0xbb, 0xbf] {
98      content[3..].to_owned()
99    } else {
100      content
101    };
102
103    Xsd::new(name, vis, &content, module_namespace_mappings)
104  }
105
106  pub fn implement(&self, target_prefix: &Option<String>) -> TokenStream {
107    let schema = self
108      .schema
109      .implement(&TokenStream::new(), target_prefix, &self.context);
110
111    let mod_name = format_ident!("{}", self.name.to_snake_case());
112    let vis = &self.vis;
113
114    quote! {
115        mod #mod_name {
116            #schema
117        }
118
119        #vis use #mod_name::*;
120    }
121  }
122}