255 lines
9.5 KiB
Rust
255 lines
9.5 KiB
Rust
use xml::reader::XmlEvent as ReadEvent;
|
|
use yaserde::{ser, YaDeserialize as YaDeserializeTrait, YaSerialize as YaSerializeTrait};
|
|
|
|
#[derive(Debug, PartialEq, Default)]
|
|
pub struct RawXml(String);
|
|
|
|
impl YaDeserializeTrait for RawXml {
|
|
fn deserialize<R: std::io::Read>(
|
|
reader: &mut yaserde::de::Deserializer<R>,
|
|
) -> Result<Self, String> {
|
|
let mut buffer = String::new();
|
|
let mut depth = 0;
|
|
|
|
let own_name = match reader.peek()? {
|
|
ReadEvent::StartElement { name, .. } => name.local_name.clone(),
|
|
_ => return Err("RawXml Should start deserializing with StartElement".to_string()),
|
|
};
|
|
println!("RawXml deserialize from root element name : {own_name}");
|
|
loop {
|
|
let current_event = reader.peek()?.to_owned();
|
|
match current_event.clone() {
|
|
ReadEvent::StartElement {
|
|
name, attributes, ..
|
|
} => {
|
|
println!("StartElement {name} depth {depth}");
|
|
depth += 1;
|
|
let mut attr_string = String::new();
|
|
attributes.iter().for_each(|a| {
|
|
attr_string.push_str(&format!(r#" {}="{}""#, &a.name, &a.value));
|
|
});
|
|
buffer.push_str(&format!("<{}{}>", name, attr_string));
|
|
let _event = reader.next_event()?;
|
|
}
|
|
ReadEvent::EndElement { name } => {
|
|
println!("EndElement {name} depth {depth}");
|
|
depth -= 1;
|
|
buffer.push_str(&format!("</{}>", name));
|
|
println!(
|
|
"Checking if name.local_name {} matches own_name {} at depth {depth}",
|
|
&name.local_name, &own_name
|
|
);
|
|
if name.local_name == own_name && depth == 0 {
|
|
println!(
|
|
"Found next EndElement is closing my struct, breaking out of loop"
|
|
);
|
|
break;
|
|
} else {
|
|
let _event = reader.next_event()?;
|
|
}
|
|
}
|
|
ReadEvent::Characters(content) => {
|
|
println!("Characters {content} depth {depth}");
|
|
buffer.push_str(&content);
|
|
let _event = reader.next_event()?;
|
|
}
|
|
ReadEvent::StartDocument {
|
|
version,
|
|
encoding,
|
|
standalone,
|
|
} => todo!(
|
|
"StartDocument {:?} {:?} {:?}",
|
|
version,
|
|
encoding,
|
|
standalone
|
|
),
|
|
ReadEvent::EndDocument => todo!(),
|
|
ReadEvent::ProcessingInstruction { name, data } => {
|
|
todo!("ProcessingInstruction {:?}, {:?}", name, data)
|
|
}
|
|
ReadEvent::CData(cdata) => todo!("CData, {:?}", cdata),
|
|
ReadEvent::Comment(comment) => todo!("Comment, {:?}", comment),
|
|
ReadEvent::Whitespace(whitespace) => todo!("Whitespace, {:?}", whitespace),
|
|
}
|
|
let next = reader.peek()?;
|
|
println!(
|
|
"Processing done on \ncurrent_event : {:?} \nnext : {:?}",
|
|
¤t_event, &next
|
|
);
|
|
}
|
|
|
|
println!("buffered events {buffer}");
|
|
|
|
Ok(RawXml(buffer))
|
|
}
|
|
}
|
|
|
|
impl YaSerializeTrait for RawXml {
|
|
fn serialize<W: std::io::Write>(&self, writer: &mut ser::Serializer<W>) -> Result<(), String> {
|
|
let content = self.0.clone();
|
|
let content = xml::EventReader::from_str(content.as_str());
|
|
let mut reader = yaserde::de::Deserializer::new(content);
|
|
loop {
|
|
let e = reader.next_event()?;
|
|
if let ReadEvent::EndDocument = e {
|
|
break;
|
|
}
|
|
writer
|
|
.write(e.as_writer_event().unwrap())
|
|
.expect("Writer should write write event");
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn serialize_attributes(
|
|
&self,
|
|
attributes: Vec<xml::attribute::OwnedAttribute>,
|
|
namespace: xml::namespace::Namespace,
|
|
) -> Result<
|
|
(
|
|
Vec<xml::attribute::OwnedAttribute>,
|
|
xml::namespace::Namespace,
|
|
),
|
|
String,
|
|
> {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use crate::infra::yaserde::to_xml_str;
|
|
|
|
use super::*;
|
|
use pretty_assertions::assert_eq;
|
|
use yaserde_derive::YaDeserialize;
|
|
use yaserde_derive::YaSerialize;
|
|
|
|
#[derive(Debug, PartialEq, Default, YaDeserialize)]
|
|
pub struct Parent {
|
|
// pub rawxml_child: RawXml,
|
|
pub string_child: String,
|
|
pub child_child: Child,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Default, YaDeserialize)]
|
|
pub struct Child {
|
|
pub child_val: String,
|
|
pub child_val2: String,
|
|
pub child_option: Option<String>,
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_buffer_empty_element() {
|
|
let rawxml: RawXml = yaserde::de::from_str("<something/>").unwrap();
|
|
assert_eq!(rawxml.0, String::from("<something></something>"));
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_buffer_elements_with_different_case_as_they_are() {
|
|
let xml = "<xml><Some_thing></Some_thing><something></something></xml>";
|
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(rawxml.0, String::from(xml));
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_buffer_elements_with_attributes() {
|
|
let xml = r#"<xml version="ababa"><Some_thing></Some_thing><something></something></xml>"#;
|
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(rawxml.0, String::from(xml));
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_handle_complex_documents() {
|
|
let xml = r#"<xml><OpenVPN version="1.0.0"><Overwrites></Overwrites><Instances></Instances><StaticKeys></StaticKeys></OpenVPN><Gateways version="0.0.1"></Gateways><HAProxy version="4.0.0"><general><enabled>1</enabled><gracefulStop>0</gracefulStop><hardStopAfter>60s</hardStopAfter><closeSpreadTime></closeSpreadTime><seamlessReload>0</seamlessReload><storeOcsp>0</storeOcsp><showIntro>1</showIntro><peers><enabled>0</enabled><name1></name1><listen1></listen1><port1>1024</port1><name2></name2><listen2></listen2><port2>1024</port2></peers><tuning><root>0</root><maxConnections></maxConnections><nbthread>1</nbthread><sslServerVerify>ignore</sslServerVerify><maxDHSize>2048</maxDHSize><bufferSize>16384</bufferSize></tuning></general></HAProxy></xml>"#;
|
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(rawxml.0, String::from(xml));
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_serialize_simple_documents() {
|
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><xml />"#;
|
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(yaserde::ser::to_string(&rawxml).unwrap(), xml);
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_serialize_complex_documents() {
|
|
let xml = r#"<?xml version="1.0"?>
|
|
<xml>
|
|
<OpenVPN version="1.0.0">
|
|
<Overwrites/>
|
|
<Instances/>
|
|
<StaticKeys/>
|
|
</OpenVPN>
|
|
<Gateways version="0.0.1"/>
|
|
<HAProxy version="4.0.0">
|
|
<general>
|
|
<enabled>1</enabled>
|
|
<gracefulStop>0</gracefulStop>
|
|
<hardStopAfter>60s</hardStopAfter>
|
|
<closeSpreadTime/>
|
|
<seamlessReload>0</seamlessReload>
|
|
<storeOcsp>0</storeOcsp>
|
|
<showIntro>1</showIntro>
|
|
<peers>
|
|
<enabled>0</enabled>
|
|
<name1/>
|
|
<listen1/>
|
|
<port1>1024</port1>
|
|
<name2/>
|
|
<listen2/>
|
|
<port2>1024</port2>
|
|
</peers>
|
|
<tuning>
|
|
<root>0</root>
|
|
<maxConnections/>
|
|
<nbthread>1</nbthread>
|
|
<sslServerVerify>ignore</sslServerVerify>
|
|
<maxDHSize>2048</maxDHSize>
|
|
<bufferSize>16384</bufferSize>
|
|
</tuning>
|
|
</general>
|
|
</HAProxy>
|
|
</xml>
|
|
"#;
|
|
let rawxml: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(to_xml_str(&rawxml).unwrap(), xml);
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_allow_siblings_before() {
|
|
#[derive(YaDeserialize, YaSerialize)]
|
|
struct Config {
|
|
paul: Vec<String>,
|
|
raw: RawXml,
|
|
}
|
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><paul>bobob</paul><paul>patate</paul><raw>allo something</raw></Config>"#;
|
|
let config: Config = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_allow_siblings_after() {
|
|
#[derive(YaDeserialize, YaSerialize)]
|
|
struct Config {
|
|
raw: RawXml,
|
|
paul: Vec<String>,
|
|
}
|
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><raw>allo something</raw><paul>bobob</paul><paul>patate</paul></Config>"#;
|
|
let config: Config = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(config.paul.get(0).unwrap(), "bobob");
|
|
assert_eq!(config.paul.get(1).unwrap(), "patate");
|
|
assert_eq!(config.paul.len(), 2);
|
|
assert_eq!(config.raw.0, "<raw>allo something</raw>");
|
|
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
|
}
|
|
|
|
#[test]
|
|
fn rawxml_should_allow_being_end_of_document() {
|
|
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Config><raw>allo something</raw><paul>bobob</paul><paul>patate</paul></Config>"#;
|
|
let config: RawXml = yaserde::de::from_str(xml).unwrap();
|
|
assert_eq!(yaserde::ser::to_string(&config).unwrap(), xml);
|
|
}
|
|
}
|