#![allow(clippy::single_match)] use quick_xml::{ escape::escape, events::{attributes::Attributes, BytesText, Event}, name::ResolveResult, NsReader, }; use raxb::{ de::{XmlDeserialize, XmlDeserializeError, XmlDeserializeResult}, ser::{XmlSerialize, XmlSerializeError}, ty::{XmlTag, XmlTargetNs, S}, }; use std::io::BufRead; #[derive(Debug)] pub struct F { pub h: Option, pub j: String, } impl XmlDeserialize for F { fn xml_deserialize( reader: &mut NsReader, _target_ns: XmlTag, tag: XmlTargetNs, _attributes: Attributes, _is_empty: bool, ) -> XmlDeserializeResult where Self: Sized, R: BufRead, { let mut buf = Vec::::new(); let mut h = Option::::None; let mut j = Option::::None; loop { match reader.read_resolved_event_into(&mut buf)? { (ResolveResult::Unbound, Event::Start(ev)) => match ev.local_name().as_ref() { b"h" => { let mut buffer: Vec = Vec::::new(); if let (ResolveResult::Unbound, Event::Text(t)) = reader.read_resolved_event_into(&mut buffer)? { h = Some(t.unescape()?.to_string()); } } b"j" => { let mut buffer: Vec = Vec::::new(); if let (ResolveResult::Unbound, Event::Text(t)) = reader.read_resolved_event_into(&mut buffer)? { j = Some(t.unescape()?.to_string()); } } _ => { let mut buffer: Vec = Vec::::new(); reader.read_to_end_into(ev.name(), &mut buffer)?; } }, (ResolveResult::Unbound, Event::End(e)) if e.local_name().as_ref() == tag => { break; } (ResolveResult::Unbound, Event::Eof) => { break; } _ => {} } } Ok(Self { h, j: j.ok_or(XmlDeserializeError::MissingElement(S(b"j")))?, }) } } impl XmlSerialize for F { fn xml_serialize( &self, tag: &str, writer: &mut quick_xml::Writer, ) -> raxb::ser::XmlSerializeResult<()> { writer .create_element(tag) .write_inner_content::<_, XmlSerializeError>(|writer| { if let Some(v) = self.h.as_ref() { writer .create_element("h") .write_text_content(BytesText::from_escaped(escape(v)))?; } writer .create_element("j") .write_text_content(BytesText::from_escaped(escape(&self.j)))?; Ok(()) })?; Ok(()) } } #[derive(Debug)] pub struct D { pub name: String, pub e: Vec, pub f: Vec, } impl XmlDeserialize for D { fn xml_deserialize( reader: &mut NsReader, target_ns: XmlTag, tag: XmlTargetNs, attributes: Attributes, _is_empty: bool, ) -> XmlDeserializeResult where Self: Sized, R: BufRead, { let mut buf = Vec::::new(); let mut name = Option::::None; for attr in attributes.flatten() { match attr.key.local_name().as_ref() { b"name" => { name = Some(String::from_utf8(attr.value.to_vec())?); } _ => {} } } let mut e = Vec::::default(); let mut f = Vec::::default(); loop { match reader.read_resolved_event_into(&mut buf)? { (ResolveResult::Unbound, Event::Start(ev)) => match ev.local_name().as_ref() { b"e" => { let mut buffer: Vec = Vec::::new(); if let (ResolveResult::Unbound, Event::Text(t)) = reader.read_resolved_event_into(&mut buffer)? { let v = t.unescape()?.parse::()?; e.push(v); } } b"f" => { f.push(F::xml_deserialize( reader, target_ns, b"f", ev.attributes(), false, )?); } _ => { let mut buffer: Vec = Vec::::new(); reader.read_to_end_into(ev.name(), &mut buffer)?; } }, (ResolveResult::Unbound, Event::End(e)) if e.local_name().as_ref() == tag => { break; } (ResolveResult::Unbound, Event::Eof) => { break; } _ => {} } } Ok(Self { name: name.ok_or(XmlDeserializeError::MissingAttribute(S(b"name")))?, e, f, }) } } impl XmlSerialize for D { fn xml_serialize( &self, tag: &str, writer: &mut quick_xml::Writer, ) -> raxb::ser::XmlSerializeResult<()> { writer .create_element(tag) .with_attribute(("name", self.name.as_str())) .write_inner_content::<_, XmlSerializeError>(|writer| { for v in self.e.iter() { writer .create_element("e") .write_text_content(BytesText::from_escaped(escape(&v.to_string())))?; } for v in self.f.iter() { v.xml_serialize("f", writer)?; } Ok(()) })?; Ok(()) } } #[derive(Debug)] pub struct A { pub id: String, pub b: bool, pub c: String, pub d: D, } impl XmlDeserialize for A { fn root() -> Option { Some(b"a") } fn xml_deserialize( reader: &mut NsReader, target_ns: XmlTag, tag: XmlTargetNs, attributes: Attributes, _is_empty: bool, ) -> XmlDeserializeResult where Self: Sized, R: BufRead, { let mut buf = Vec::::new(); let mut id = Option::::None; for attr in attributes.flatten() { match attr.key.local_name().as_ref() { b"id" => { id = Some(String::from_utf8(attr.value.to_vec())?); } _ => {} } } let mut b = Option::::None; let mut c = Option::::None; let mut d = Option::::None; loop { match reader.read_resolved_event_into(&mut buf)? { (ResolveResult::Unbound, Event::Start(e)) => match e.local_name().as_ref() { b"c" => { let mut buffer: Vec = Vec::::new(); if let (ResolveResult::Unbound, Event::Text(t)) = reader.read_resolved_event_into(&mut buffer)? { c = Some(t.unescape()?.to_string()); } } b"d" => { d = Some(D::xml_deserialize( reader, target_ns, b"d", e.attributes(), false, )?) } _ => { let mut buffer: Vec = Vec::::new(); reader.read_to_end_into(e.name(), &mut buffer)?; } }, (ResolveResult::Unbound, Event::Empty(e)) => match e.local_name().as_ref() { b"b" => { b = Some(true); } _ => {} }, (ResolveResult::Unbound, Event::End(e)) if e.local_name().as_ref() == tag => { break; } (_, Event::Eof) => { break; } _ => {} } } Ok(Self { id: id.ok_or(XmlDeserializeError::MissingAttribute(S(b"id")))?, b: b.ok_or(XmlDeserializeError::MissingElement(S(b"b")))?, c: c.ok_or(XmlDeserializeError::MissingElement(S(b"c")))?, d: d.ok_or(XmlDeserializeError::MissingElement(S(b"d")))?, }) } } impl XmlSerialize for A { fn root() -> Option { Some(b"a") } fn xml_serialize( &self, tag: &str, writer: &mut quick_xml::Writer, ) -> raxb::ser::XmlSerializeResult<()> { writer .create_element(tag) .with_attribute(("id", self.id.as_str())) .write_inner_content::<_, XmlSerializeError>(|writer| { if self.b { writer.create_element("b").write_empty()?; } writer .create_element("c") .write_text_content(BytesText::new(&self.c))?; self.d.xml_serialize("d", writer)?; Ok(()) })?; Ok(()) } } #[test] fn test_serialize_manual() -> anyhow::Result<()> { let a = A { id: "root".to_string(), b: true, c: "foo".to_string(), d: D { name: "foobar".to_string(), e: vec![1, 2, 3], f: vec![ F { h: Some("bar1".to_string()), j: "baz2".to_string(), }, F { h: None, j: "baz".to_string(), }, ], }, }; let xml = raxb::ser::to_string(&a)?; assert_eq!( r#"foo123bar1baz2baz"#, xml ); Ok(()) } #[test] fn test_deserialize_manual() -> anyhow::Result<()> { let xml = r#" foo 1 2 3 bar1 baz2 baz "#; let a = raxb::de::from_str::(xml)?; assert_eq!(a.id, "root"); assert!(a.b); assert_eq!(a.c, "foo"); assert_eq!(a.d.name, "foobar"); assert_eq!(a.d.e, vec![1, 2, 3]); assert_eq!(a.d.f.first().unwrap().h.as_ref().unwrap(), "bar1"); assert_eq!(a.d.f.first().unwrap().j, "baz2"); assert!(a.d.f.get(1).unwrap().h.is_none()); assert_eq!(a.d.f.get(1).unwrap().j, "baz"); Ok(()) } #[test] fn test_deserialize_manual_skipping_unknown_fields() -> anyhow::Result<()> { let xml = r#" foo unknown 1 2 1 2 3 3 bar1 baz2 recurse baz "#; let a = raxb::de::from_str::(xml)?; assert!(a.b); assert_eq!(a.c, "foo"); assert_eq!(a.d.name, "foobar"); assert_eq!(a.d.e, vec![1, 2, 3]); assert_eq!(a.d.f.first().unwrap().h.as_ref().unwrap(), "bar1"); assert_eq!(a.d.f.first().unwrap().j, "baz2"); assert!(a.d.f.get(1).unwrap().h.is_none()); assert_eq!(a.d.f.get(1).unwrap().j, "baz"); Ok(()) }