1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Entity resolver module
use Infallible;
use Error;
use crateresolve_predefined_entity;
use crateBytesText;
/// Used to resolve unknown entities while parsing
///
/// # Example
///
/// ```
/// # use serde::Deserialize;
/// use std::collections::BTreeMap;
/// use std::string::FromUtf8Error;
/// use oxixml_xml::de::{Deserializer, EntityResolver};
/// use oxixml_xml::events::BytesText;
///
/// #[derive(Default)]
/// struct DocTypeEntityResolver {
/// map: BTreeMap<String, String>,
/// }
///
/// impl EntityResolver for DocTypeEntityResolver {
/// type Error = FromUtf8Error;
///
/// fn capture(&mut self, doctype: BytesText) -> Result<(), Self::Error> {
/// // We do not focus on true parsing in this example: this only handles
/// // `<!ENTITY name "value">` declarations. You should use a dedicated
/// // DTD parser in real code.
/// let text = String::from_utf8(doctype.to_vec())?;
/// let mut rest = text.as_str();
/// while let Some(start) = rest.find("<!ENTITY") {
/// rest = rest[start + "<!ENTITY".len()..].trim_start();
/// let name_len = rest.find(char::is_whitespace).unwrap_or(rest.len());
/// let name = rest[..name_len].to_string();
/// rest = &rest[name_len..];
///
/// let Some(open) = rest.find('"') else { break };
/// rest = &rest[open + 1..];
/// let Some(close) = rest.find('"') else { break };
/// self.map.insert(name, rest[..close].to_string());
/// rest = &rest[close + 1..];
/// }
/// Ok(())
/// }
///
/// fn resolve(&self, entity: &str) -> Option<&str> {
/// self.map.get(entity).map(|s| s.as_str())
/// }
/// }
///
/// let xml_reader = br#"
/// <!DOCTYPE dict[ <!ENTITY e1 "entity 1"> ]>
/// <root>
/// <entity_one>&e1;</entity_one>
/// </root>
/// "#.as_ref();
///
/// let mut de = Deserializer::with_resolver(
/// xml_reader,
/// DocTypeEntityResolver::default(),
/// );
/// let data: BTreeMap<String, String> = BTreeMap::deserialize(&mut de).expect("should be Ok");
///
/// assert_eq!(data.get("entity_one"), Some(&"entity 1".to_string()));
/// ```
/// An [`EntityResolver`] that resolves only predefined entities:
///
/// | Entity | Resolution
/// |--------|------------
/// |`<` | `<`
/// |`>` | `>`
/// |`&` | `&`
/// |`'`| `'`
/// |`"`| `"`
;