1use alloc::{
10 borrow::{Cow, ToOwned},
11 boxed::Box,
12 vec::IntoIter,
13};
14use core::marker::PhantomData;
15
16use minidom::{Element, Node};
17
18use rxml::{
19 parser::EventMetrics,
20 writer::{SimpleNamespaces, TrackNamespace},
21 AttrMap, Event, Name, NameStr, Namespace, NcName, NcNameStr,
22};
23
24use crate::{
25 error::{Error, FromEventsError},
26 rxml_util::{EventToItem, Item},
27 AsXml, Context, FromEventsBuilder, FromXml,
28};
29
30enum IntoEventsInner {
34 Header(Element),
38
39 Nodes {
41 remaining: IntoIter<Node>,
43
44 nested: Option<Box<IntoEvents>>,
47 },
48
49 Fin,
56}
57
58#[deprecated(
67 since = "0.1.3",
68 note = "obsolete since the transition to AsXml. no replacement."
69)]
70pub fn make_start_ev_parts(el: &Element) -> Result<(rxml::QName, AttrMap), Error> {
73 let name = NcName::try_from(el.name())?;
74 let namespace = Namespace::from(el.ns());
75
76 let mut attrs = AttrMap::new();
77 for (name, value) in el.attrs() {
78 let name = Name::try_from(name)?;
79 let (prefix, name) = name.split_name()?;
80 let namespace = if let Some(prefix) = prefix {
81 if prefix == "xml" {
82 Namespace::XML
83 } else {
84 let ns = match el.prefixes.get(&Some(prefix.into())) {
85 Some(v) => v,
86 None => {
87 panic!("undeclared xml namespace prefix in minidom::Element")
88 }
89 };
90 Namespace::from(ns.to_owned())
91 }
92 } else {
93 Namespace::NONE
94 };
95
96 attrs.insert(namespace, name, value.to_owned());
97 }
98
99 Ok(((namespace, name), attrs))
100}
101
102impl IntoEventsInner {
103 fn next(&mut self) -> Result<Option<Event>, Error> {
104 match self {
105 IntoEventsInner::Header(ref mut el) => {
106 #[allow(deprecated)]
107 let (qname, attrs) = make_start_ev_parts(el)?;
108 let event = Event::StartElement(EventMetrics::zero(), qname, attrs);
109
110 *self = IntoEventsInner::Nodes {
111 remaining: el.take_nodes().into_iter(),
112 nested: None,
113 };
114 Ok(Some(event))
115 }
116 IntoEventsInner::Nodes {
117 ref mut nested,
118 ref mut remaining,
119 } => {
120 loop {
121 if let Some(nested) = nested.as_mut() {
122 if let Some(ev) = nested.next() {
123 return Some(ev).transpose();
124 }
125 }
126 match remaining.next() {
127 Some(Node::Text(text)) => {
128 return Ok(Some(Event::Text(EventMetrics::zero(), text)));
129 }
130 Some(Node::Element(el)) => {
131 *nested = Some(Box::new(IntoEvents::new(el)));
132 }
134 None => {
135 *self = IntoEventsInner::Fin;
137 return Ok(Some(Event::EndElement(EventMetrics::zero())));
138 }
139 }
140 }
141 }
142 IntoEventsInner::Fin => Ok(None),
143 }
144 }
145}
146
147struct IntoEvents(IntoEventsInner);
154
155impl IntoEvents {
156 fn new(el: Element) -> Self {
157 IntoEvents(IntoEventsInner::Header(el))
158 }
159}
160
161impl Iterator for IntoEvents {
162 type Item = Result<Event, Error>;
163
164 fn next(&mut self) -> Option<Self::Item> {
165 self.0.next().transpose()
166 }
167}
168
169enum AsXmlState<'a> {
170 Header { element: &'a Element },
173
174 Attributes {
176 element: &'a Element,
179
180 attributes: minidom::element::Attrs<'a>,
182 },
183
184 Nodes {
186 nodes: minidom::element::Nodes<'a>,
188
189 nested: Option<Box<ElementAsXml<'a>>>,
192 },
193}
194
195pub struct ElementAsXml<'a>(Option<AsXmlState<'a>>);
201
202impl<'a> Iterator for ElementAsXml<'a> {
203 type Item = Result<Item<'a>, Error>;
204
205 fn next(&mut self) -> Option<Self::Item> {
206 match self.0 {
207 None => None,
208 Some(AsXmlState::Header { element }) => {
209 let item = Item::ElementHeadStart(
210 Namespace::from(element.ns()),
211 Cow::Borrowed(match <&NcNameStr>::try_from(element.name()) {
212 Ok(v) => v,
213 Err(e) => {
214 self.0 = None;
215 return Some(Err(e.into()));
216 }
217 }),
218 );
219 self.0 = Some(AsXmlState::Attributes {
220 element,
221 attributes: element.attrs(),
222 });
223 Some(Ok(item))
224 }
225 Some(AsXmlState::Attributes {
226 ref mut attributes,
227 element,
228 }) => {
229 if let Some((name, value)) = attributes.next() {
230 let name = match <&NameStr>::try_from(name) {
231 Ok(v) => v,
232 Err(e) => {
233 self.0 = None;
234 return Some(Err(e.into()));
235 }
236 };
237 let (prefix, name) = match name.split_name() {
238 Ok(v) => v,
239 Err(e) => {
240 self.0 = None;
241 return Some(Err(e.into()));
242 }
243 };
244 let namespace = if let Some(prefix) = prefix {
245 if prefix == "xml" {
246 Namespace::XML
247 } else {
248 let ns = match element.prefixes.get(&Some(prefix.as_str().to_owned())) {
249 Some(v) => v,
250 None => {
251 panic!("undeclared xml namespace prefix in minidom::Element")
252 }
253 };
254 Namespace::from(ns.to_owned())
255 }
256 } else {
257 Namespace::NONE
258 };
259 Some(Ok(Item::Attribute(
260 namespace,
261 Cow::Borrowed(name),
262 Cow::Borrowed(value),
263 )))
264 } else {
265 self.0 = Some(AsXmlState::Nodes {
266 nodes: element.nodes(),
267 nested: None,
268 });
269 Some(Ok(Item::ElementHeadEnd))
270 }
271 }
272 Some(AsXmlState::Nodes {
273 ref mut nodes,
274 ref mut nested,
275 }) => {
276 if let Some(nested) = nested.as_mut() {
277 if let Some(next) = nested.next() {
278 return Some(next);
279 }
280 }
281 *nested = None;
282 match nodes.next() {
283 None => {
284 self.0 = None;
285 Some(Ok(Item::ElementFoot))
286 }
287 Some(minidom::Node::Text(ref text)) => {
288 Some(Ok(Item::Text(Cow::Borrowed(text))))
289 }
290 Some(minidom::Node::Element(ref element)) => {
291 let mut iter = match element.as_xml_iter() {
292 Ok(v) => v,
293 Err(e) => {
294 self.0 = None;
295 return Some(Err(e));
296 }
297 };
298 let item = iter.next().unwrap();
299 *nested = Some(Box::new(iter));
300 Some(item)
301 }
302 }
303 }
304 }
305 }
306}
307
308impl AsXml for minidom::Element {
309 type ItemIter<'a> = ElementAsXml<'a>;
310
311 fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
312 Ok(ElementAsXml(Some(AsXmlState::Header { element: self })))
313 }
314}
315
316pub struct ElementFromEvents {
322 inner: Option<Element>,
323 nested: Option<Box<ElementFromEvents>>,
324}
325
326impl ElementFromEvents {
327 pub fn new(qname: rxml::QName, attrs: rxml::AttrMap) -> Self {
333 let mut prefixes = SimpleNamespaces::new();
334 let mut builder = Element::builder(qname.1, qname.0);
335 for ((namespace, name), value) in attrs.into_iter() {
336 if namespace.is_none() {
337 builder = builder.attr(name, value);
338 } else {
339 let (is_new, prefix) = prefixes.declare_with_auto_prefix(namespace.clone());
340 let name = prefix.with_suffix(&name);
341 if is_new {
342 builder = builder
343 .prefix(
344 Some(prefix.as_str().to_owned()),
345 namespace.as_str().to_owned(),
346 )
347 .unwrap();
348 }
349 builder = builder.attr(name, value);
350 }
351 }
352
353 let element = builder.build();
354 Self {
355 inner: Some(element),
356 nested: None,
357 }
358 }
359}
360
361impl FromEventsBuilder for ElementFromEvents {
362 type Output = minidom::Element;
363
364 fn feed(&mut self, ev: Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
365 let inner = self
366 .inner
367 .as_mut()
368 .expect("feed() called after it finished");
369 if let Some(nested) = self.nested.as_mut() {
370 match nested.feed(ev, ctx)? {
371 Some(v) => {
372 inner.append_child(v);
373 self.nested = None;
374 return Ok(None);
375 }
376 None => return Ok(None),
377 }
378 }
379 match ev {
380 Event::XmlDeclaration(_, _) => Ok(None),
381 Event::StartElement(_, qname, attrs) => {
382 let nested = match Element::from_events(qname, attrs, ctx) {
383 Ok(v) => v,
384 Err(FromEventsError::Invalid(e)) => return Err(e),
385 Err(FromEventsError::Mismatch { .. }) => {
386 unreachable!("<Element as FromXml>::from_events should accept everything!")
387 }
388 };
389 self.nested = Some(Box::new(nested));
390 Ok(None)
391 }
392 Event::Text(_, text) => {
393 inner.append_text_node(text);
394 Ok(None)
395 }
396 Event::EndElement(_) => Ok(Some(self.inner.take().unwrap())),
397 }
398 }
399}
400
401impl FromXml for Element {
402 type Builder = ElementFromEvents;
403
404 fn from_events(
405 qname: rxml::QName,
406 attrs: rxml::AttrMap,
407 _ctx: &Context<'_>,
408 ) -> Result<Self::Builder, FromEventsError> {
409 Ok(Self::Builder::new(qname, attrs))
410 }
411}
412
413pub struct FromEventsViaElement<T> {
416 inner: ElementFromEvents,
417 _phantom: PhantomData<T>,
422}
423
424impl<E, T: TryFrom<minidom::Element, Error = E>> FromEventsViaElement<T>
425where
426 Error: From<E>,
427{
428 pub fn new(qname: rxml::QName, attrs: rxml::AttrMap) -> Result<Self, FromEventsError> {
430 Ok(Self {
431 _phantom: PhantomData,
432 inner: Element::from_events(
433 qname,
434 attrs,
435 &Context::empty(),
438 )?,
439 })
440 }
441}
442
443impl<E, T: TryFrom<minidom::Element, Error = E>> FromEventsBuilder for FromEventsViaElement<T>
444where
445 Error: From<E>,
446{
447 type Output = T;
448
449 fn feed(&mut self, ev: Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
450 match self.inner.feed(ev, ctx) {
451 Ok(Some(v)) => Ok(Some(v.try_into()?)),
452 Ok(None) => Ok(None),
453 Err(e) => Err(e),
454 }
455 }
456}
457
458pub struct AsItemsViaElement<'x> {
466 iter: EventToItem<IntoEvents>,
467 lifetime_binding: PhantomData<Item<'x>>,
468}
469
470impl AsItemsViaElement<'_> {
471 pub fn new<E, T>(value: T) -> Result<Self, crate::error::Error>
473 where
474 Error: From<E>,
475 minidom::Element: TryFrom<T, Error = E>,
476 {
477 let element: minidom::Element = value.try_into()?;
478 Ok(Self {
479 iter: EventToItem::new(IntoEvents::new(element)),
480 lifetime_binding: PhantomData,
481 })
482 }
483}
484
485impl<'x> Iterator for AsItemsViaElement<'x> {
486 type Item = Result<Item<'x>, Error>;
487
488 fn next(&mut self) -> Option<Self::Item> {
489 self.iter.next().map(|x| x.map(Item::into_owned))
490 }
491}
492
493#[cfg(test)]
494mod tests {
495 use super::*;
496
497 #[test]
498 fn transform_element_is_equivalent() {
499 let el: Element = "<foo xmlns='urn:a' a='b' c='d'><child a='x'/><child a='y'>some text</child><child xmlns='urn:b'><nested-child/></child></foo>".parse().unwrap();
500 let transformed: Element = crate::transform(&el).unwrap();
501 assert_eq!(el, transformed);
502 }
503}