1#[cfg(doctest)]
5#[doc = include_str!("../../README.md")]
6struct _RootReadMeDocTests;
7
8#[cfg(doctest)]
9#[doc = include_str!("../README.md")]
10struct _ReadMeDocTests;
11
12use ::quick_xml::name::ResolveResult;
13use core::str;
14
15use xmlity::{ser::IncludePrefix, ExpandedName, LocalName, Prefix, QName, XmlNamespace};
16
17pub mod de;
18pub mod ser;
19
20pub use de::{from_str, Deserializer};
21use quick_xml::name::{LocalName as QuickLocalName, Prefix as QuickPrefix, QName as QuickName};
22pub use ser::{to_string, Serializer};
23
24#[derive(Debug, thiserror::Error)]
25pub enum Error {
26 #[error("Quick XML error: {0}")]
27 QuickXml(#[from] quick_xml::Error),
28 #[error("Attribute error: {0}")]
29 AttrError(#[from] quick_xml::events::attributes::AttrError),
30 #[error("IO error: {0}")]
31 Io(#[from] std::io::Error),
32 #[error("Unexpected: {0}")]
33 Unexpected(xmlity::de::Unexpected),
34 #[error("Custom: {0}")]
35 Custom(String),
36 #[error("Wrong name: expected {expected:?}, got {actual:?}")]
37 WrongName {
38 actual: Box<ExpandedName<'static>>,
39 expected: Box<ExpandedName<'static>>,
40 },
41 #[error("Unknown child")]
42 UnknownChild,
43 #[error("Invalid UTF-8: {0}")]
44 InvalidUtf8(#[from] std::string::FromUtf8Error),
45 #[error("Invalid string")]
46 InvalidString,
47 #[error("Missing field: {field}")]
48 MissingField { field: String },
49 #[error("No possible variant: {ident}")]
50 NoPossibleVariant { ident: String },
51 #[error("Missing data")]
52 MissingData,
53}
54
55impl xmlity::de::Error for Error {
56 fn custom<T: ToString>(msg: T) -> Self {
57 Error::Custom(msg.to_string())
58 }
59
60 fn wrong_name(actual: &ExpandedName<'_>, expected: &ExpandedName<'_>) -> Self {
61 Error::WrongName {
62 actual: Box::new(actual.clone().into_owned()),
63 expected: Box::new(expected.clone().into_owned()),
64 }
65 }
66
67 fn unexpected_visit<T>(unexpected: xmlity::de::Unexpected, _expected: &T) -> Self {
68 Error::Unexpected(unexpected)
69 }
70
71 fn missing_field(field: &str) -> Self {
72 Error::MissingField {
73 field: field.to_string(),
74 }
75 }
76
77 fn no_possible_variant(ident: &str) -> Self {
78 Error::NoPossibleVariant {
79 ident: ident.to_string(),
80 }
81 }
82
83 fn missing_data() -> Self {
84 Error::MissingData
85 }
86
87 fn unknown_child() -> Self {
88 Error::UnknownChild
89 }
90
91 fn invalid_string() -> Self {
92 Error::InvalidString
93 }
94}
95
96impl xmlity::ser::Error for Error {
97 fn custom<T: ToString>(msg: T) -> Self {
98 Error::Custom(msg.to_string())
99 }
100}
101
102pub trait HasQuickXmlAlternative {
103 type QuickXmlAlternative;
104
105 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self;
106}
107
108impl<'a> HasQuickXmlAlternative for QName<'a> {
109 type QuickXmlAlternative = QuickName<'a>;
110
111 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self {
112 QName::new(
113 quick_xml.prefix().map(Prefix::from_quick_xml),
114 LocalName::from_quick_xml(quick_xml.local_name()),
115 )
116 }
117}
118
119impl<'a> HasQuickXmlAlternative for Prefix<'a> {
120 type QuickXmlAlternative = QuickPrefix<'a>;
121 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self {
122 Self::new(str::from_utf8(quick_xml.into_inner()).expect("prefix should be valid utf8"))
123 .expect("A quick xml prefix should be valid")
124 }
125}
126
127impl<'a> HasQuickXmlAlternative for LocalName<'a> {
128 type QuickXmlAlternative = QuickLocalName<'a>;
129 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self {
130 Self::new(str::from_utf8(quick_xml.into_inner()).expect("local name should be valid utf8"))
131 .expect("A quick xml local name should be valid")
132 }
133}
134
135pub struct OwnedQuickName(Vec<u8>);
136
137impl OwnedQuickName {
138 pub fn new(name: &QName<'_>) -> Self {
139 Self(name.to_string().into_bytes())
140 }
141
142 pub fn as_ref(&self) -> QuickName<'_> {
143 QuickName(&self.0[..])
144 }
145}
146
147pub fn xml_namespace_from_resolve_result(value: ResolveResult<'_>) -> Option<XmlNamespace<'_>> {
148 match value {
149 ResolveResult::Bound(namespace) => Some(
150 XmlNamespace::new(str::from_utf8(namespace.0).expect("namespace should be valid utf8"))
151 .unwrap(),
152 ),
153 _ => None,
154 }
155}
156
157#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
158pub struct Attribute<'a> {
159 pub name: ExpandedName<'a>,
160 pub value: String,
161 pub enforce_prefix: IncludePrefix,
162 pub preferred_prefix: Option<Prefix<'a>>,
163}
164
165impl<'a> Attribute<'a> {
166 pub fn resolve(self, resolved_prefix: Option<Prefix<'a>>) -> ResolvedAttribute<'a> {
167 ResolvedAttribute {
168 name: self.name.to_q_name(resolved_prefix),
169 value: self.value,
170 }
171 }
172}
173
174#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
175pub struct ResolvedAttribute<'a> {
176 pub name: QName<'a>,
177 pub value: String,
178}
179
180fn declaration_into_attribute(xmlns: XmlnsDeclaration<'_>) -> ResolvedAttribute<'_> {
181 ResolvedAttribute {
182 name: XmlnsDeclaration::xmlns_qname(xmlns.prefix),
183 value: xmlns.namespace.as_str().to_owned(),
184 }
185}
186
187#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
189pub struct XmlnsDeclaration<'a> {
190 pub prefix: Prefix<'a>,
191 pub namespace: XmlNamespace<'a>,
192}
193
194impl<'a> XmlnsDeclaration<'a> {
195 pub fn new(prefix: Prefix<'a>, namespace: XmlNamespace<'a>) -> Self {
196 Self { prefix, namespace }
197 }
198
199 pub fn into_owned(self) -> XmlnsDeclaration<'static> {
200 XmlnsDeclaration {
201 prefix: self.prefix.into_owned(),
202 namespace: self.namespace.into_owned(),
203 }
204 }
205
206 pub fn prefix(&self) -> &Prefix<'a> {
207 &self.prefix
208 }
209
210 pub fn namespace(&self) -> &XmlNamespace<'a> {
211 &self.namespace
212 }
213
214 pub fn xmlns_qname(prefix: Prefix<'_>) -> QName<'_> {
216 if prefix.is_default() {
217 QName::new(
218 None,
219 LocalName::new("xmlns").expect("xmlns is a valid local name"),
220 )
221 } else {
222 QName::new(
223 Some(Prefix::new("xmlns").expect("xmlns is a valid prefix")),
224 LocalName::from(prefix),
225 )
226 }
227 }
228}