Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ keywords = ["xml", "serde"]
readme = "README.md"

[dependencies]
quick-xml = { version = "0.37", features = ["serialize"] }
quick-xml = { version = "0.40", features = ["serialize"] }

[dev-dependencies]
xmlserde_derives = { path = "./derives", version = "0.12.0" }
2 changes: 1 addition & 1 deletion derives/src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ fn respan_token(mut token: TokenTree, span: Span) -> TokenTree {
token
}

fn get_generics(t: &syn::Type) -> Generic {
fn get_generics(t: &syn::Type) -> Generic<'_> {
match t {
syn::Type::Path(p) => {
let path = &p.path;
Expand Down
10 changes: 6 additions & 4 deletions derives/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ fn attr_match_branch(field: StructField) -> proc_macro2::TokenStream {
quote! {
#tag => {
use xmlserde::{XmlValue, XmlDeserialize};
let s = String::from_utf8(attr.value.into_iter().map(|c| *c).collect()).unwrap();
let s = attr.normalized_value(::xmlserde::quick_xml::XmlVersion::Implicit1_0).expect("unescape attr value").into_owned();
match #opt_ty::deserialize(&s) {
Ok(__v) => {
#ident = Some(__v);
Expand All @@ -603,7 +603,7 @@ fn attr_match_branch(field: StructField) -> proc_macro2::TokenStream {
quote! {
#tag => {
use xmlserde::{XmlValue, XmlDeserialize};
let __s = String::from_utf8(attr.value.into_iter().map(|c| *c).collect()).unwrap();
let __s = attr.normalized_value(::xmlserde::quick_xml::XmlVersion::Implicit1_0).expect("unescape attr value").into_owned();
match #t::deserialize(&__s) {
Ok(__v) => {
#tt
Expand Down Expand Up @@ -638,7 +638,8 @@ fn text_match_branch(field: StructField) -> proc_macro2::TokenStream {
quote! {
Ok(Event::Text(__s)) => {
use ::xmlserde::{XmlValue, XmlDeserialize};
let __r = __s.unescape().unwrap();
let __decoded = __s.decode().expect("decode text");
let __r = ::xmlserde::quick_xml::escape::unescape(&__decoded).expect("unescape text");
match #t::deserialize(&__r) {
Ok(__v) => {
// #ident = v;
Expand Down Expand Up @@ -832,7 +833,8 @@ fn children_match_branch(
}
Ok(Event::Text(t)) => {
use ::xmlserde::{XmlValue, XmlDeserialize};
let _str = t.unescape().expect("failed to unescape string");
let _decoded = t.decode().expect("decode text");
let _str = ::xmlserde::quick_xml::escape::unescape(&_decoded).expect("unescape text");
if _str.trim() != "" {
#untag_text_enum
}
Expand Down
30 changes: 14 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,16 @@ pub trait XmlSerialize {

impl<T: XmlSerialize> XmlSerialize for Option<T> {
fn serialize<W: Write>(&self, tag: &[u8], writer: &mut quick_xml::Writer<W>) {
match self {
Some(t) => t.serialize(tag, writer),
None => {}
if let Some(t) = self {
t.serialize(tag, writer)
}
}
}

impl<T: XmlSerialize> XmlSerialize for Vec<T> {
fn serialize<W: Write>(&self, _tag_: &[u8], _writer_: &mut quick_xml::Writer<W>) {
self.iter().for_each(|c| {
let _ = c.serialize(_tag_, _writer_);
c.serialize(_tag_, _writer_);
});
}
}
Expand Down Expand Up @@ -260,7 +259,7 @@ impl XmlSerialize for Unparsed {
let v = v as &str;
start.push_attribute((k, v));
});
if self.data.len() > 0 {
if !self.data.is_empty() {
let _ = _writer_.write_event(Event::Start(start));
self.data.iter().for_each(|e| {
let _ = _writer_.write_event(e.clone());
Expand All @@ -287,7 +286,10 @@ impl XmlDeserialize for Unparsed {
if let Ok(attr) = a {
let key =
String::from_utf8(attr.key.into_inner().to_vec()).unwrap_or(String::from(""));
let value = String::from_utf8(attr.value.to_vec()).unwrap_or(String::from(""));
let value = attr
.normalized_value(quick_xml::XmlVersion::Implicit1_0)
.map(|v| v.into_owned())
.unwrap_or(String::from(""));
attrs_vec.push((key, value))
}
});
Expand Down Expand Up @@ -396,17 +398,13 @@ where
let mut buf = Vec::<u8>::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(start)) => {
if start.name().into_inner() == root {
let result = T::deserialize(root, &mut reader, start.attributes(), false);
return Ok(result);
}
Ok(Event::Start(start)) if start.name().into_inner() == root => {
let result = T::deserialize(root, &mut reader, start.attributes(), false);
return Ok(result);
}
Ok(Event::Empty(start)) => {
if start.name().into_inner() == root {
let result = T::deserialize(root, &mut reader, start.attributes(), true);
return Ok(result);
}
Ok(Event::Empty(start)) if start.name().into_inner() == root => {
let result = T::deserialize(root, &mut reader, start.attributes(), true);
return Ok(result);
}
Ok(Event::Eof) => {
return Err(format!(
Expand Down
88 changes: 58 additions & 30 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ mod tests {
let result = xml_deserialize_from_str::<Font>(xml);
match result {
Ok(f) => {
assert_eq!(f.bold, true);
assert_eq!(f.italic, true);
assert!(f.bold);
assert!(f.italic);
assert_eq!(f.size, 12.2);
}
Err(_) => panic!(),
Expand Down Expand Up @@ -429,7 +429,7 @@ mod tests {
}

let xml = r#"<TestA><others age="16" name="Tom"><gf/><parent><f/><m name="Lisa">1999</m></parent></others></TestA>"#;
let p = xml_deserialize_from_str::<TestA>(&xml).unwrap();
let p = xml_deserialize_from_str::<TestA>(xml).unwrap();
let ser = xml_serialize(p);
assert_eq!(xml, ser);
}
Expand Down Expand Up @@ -462,7 +462,7 @@ mod tests {
}

let xml = r#"<Root><a aAttr="3"/></Root>"#;
let p = xml_deserialize_from_str::<Root>(&xml).unwrap();
let p = xml_deserialize_from_str::<Root>(xml).unwrap();
match p.dummy {
EnumA::A1(ref a) => assert_eq!(a.a_attr1, 3),
EnumA::B1(_) => panic!(),
Expand Down Expand Up @@ -499,7 +499,7 @@ mod tests {
}

let xml = r#"<Root><a aAttr="3"/><b bAttr="5"/><a aAttr="4"/></Root>"#;
let p = xml_deserialize_from_str::<Root>(&xml).unwrap();
let p = xml_deserialize_from_str::<Root>(xml).unwrap();
assert_eq!(p.dummy.len(), 3);
let ser = xml_serialize(p);
assert_eq!(xml, &ser);
Expand All @@ -523,17 +523,11 @@ mod tests {
#[xmlserde(name = b"aAttr", ty = "attr")]
pub a_attr1: u32,
}
#[derive(Debug, XmlSerialize, XmlDeserialize)]
pub struct Bstruct {
#[xmlserde(name = b"bAttr", ty = "attr")]
pub b_attr1: u32,
}

let xml = r#"<Root/>"#;
let p = xml_deserialize_from_str::<Root>(&xml).unwrap();
assert!(matches!(p.dummy, None));
let p = xml_deserialize_from_str::<Root>(xml).unwrap();
assert!(p.dummy.is_none());
let xml = r#"<Root><a aAttr="3"/></Root>"#;
let p = xml_deserialize_from_str::<Root>(&xml).unwrap();
let p = xml_deserialize_from_str::<Root>(xml).unwrap();
match p.dummy {
Some(EnumA::A1(ref a)) => assert_eq!(a.a_attr1, 3),
None => panic!(),
Expand All @@ -559,6 +553,7 @@ mod tests {
}

#[test]
#[allow(dead_code)]
fn test_generics() {
#[derive(Debug, XmlSerialize, XmlDeserialize)]
#[xmlserde(root = b"Root")]
Expand All @@ -570,7 +565,6 @@ mod tests {
#[derive(XmlSerialize)]
pub enum EnumB<T: XmlSerialize> {
#[xmlserde(name = b"a")]
#[allow(dead_code)]
A1(T),
}

Expand Down Expand Up @@ -608,14 +602,14 @@ mod tests {
}

let xml = r#"<parameter><varargs /></parameter>"#;
let p = xml_deserialize_from_str::<Parameter>(&xml).unwrap();
let p = xml_deserialize_from_str::<Parameter>(xml).unwrap();
assert!(matches!(p.ty, ParameterType::VarArgs));

let expect = xml_serialize(p);
assert_eq!(expect, "<parameter><varargs/></parameter>");

let xml = r#"<parameter><type name="n"/></parameter>"#;
let p = xml_deserialize_from_str::<Parameter>(&xml).unwrap();
let p = xml_deserialize_from_str::<Parameter>(xml).unwrap();
if let ParameterType::Type(t) = &p.ty {
assert_eq!(t.name, "n")
} else {
Expand All @@ -625,7 +619,7 @@ mod tests {
assert_eq!(expect, xml);

let xml = r#"<parameter>ttttt</parameter>"#;
let p = xml_deserialize_from_str::<Parameter>(&xml).unwrap();
let p = xml_deserialize_from_str::<Parameter>(xml).unwrap();
assert!(matches!(p.ty, ParameterType::Text(_)));
let expect = xml_serialize(p);
assert_eq!(expect, xml);
Expand Down Expand Up @@ -658,10 +652,10 @@ mod tests {
<text:span> text1 </text:span>
<text:span>text2</text:span>
</text:p>"#;
let text_p = xml_deserialize_from_str::<TextP>(&xml).unwrap();
let text_p = xml_deserialize_from_str::<TextP>(xml).unwrap();
let content = &text_p.text_p_content;
assert_eq!(content.len(), 2);
if let TextPContent::TextSpan(span) = content.get(0).unwrap() {
if let TextPContent::TextSpan(span) = content.first().unwrap() {
assert_eq!(&span.t, " text1 ")
} else {
panic!("")
Expand All @@ -679,10 +673,10 @@ mod tests {
);

let xml = r#"<text:p>abcdefg</text:p>"#;
let text_p = xml_deserialize_from_str::<TextP>(&xml).unwrap();
let text_p = xml_deserialize_from_str::<TextP>(xml).unwrap();
let content = &text_p.text_p_content;
assert_eq!(content.len(), 1);
if let TextPContent::Text(s) = content.get(0).unwrap() {
if let TextPContent::Text(s) = content.first().unwrap() {
assert_eq!(s, "abcdefg")
} else {
panic!("")
Expand All @@ -702,7 +696,7 @@ mod tests {
pub name: String,
}
let xml = r#"<pet name="Chaplin" age="1"/>"#;
let _ = xml_deserialize_from_str::<Pet>(&xml).unwrap();
let _ = xml_deserialize_from_str::<Pet>(xml).unwrap();
}

#[test]
Expand All @@ -714,7 +708,7 @@ mod tests {
pub name: String,
}
let xml = r#"<pet name="Chaplin" age="1"/>"#;
let _ = xml_deserialize_from_str::<Pet>(&xml).unwrap();
let _ = xml_deserialize_from_str::<Pet>(xml).unwrap();
}

#[test]
Expand All @@ -728,7 +722,7 @@ mod tests {
pub name: String,
}
let xml = r#"<pet name="Chaplin"><weight/></pet>"#;
let _ = xml_deserialize_from_str::<Pet>(&xml).unwrap();
let _ = xml_deserialize_from_str::<Pet>(xml).unwrap();
}

#[test]
Expand All @@ -740,7 +734,7 @@ mod tests {
pub name: String,
}
let xml = r#"<pet name="Chaplin"><weight/></pet>"#;
let _ = xml_deserialize_from_str::<Pet>(&xml).unwrap();
let _ = xml_deserialize_from_str::<Pet>(xml).unwrap();
}

// https://github.com/ImJeremyHe/xmlserde/issues/52
Expand Down Expand Up @@ -803,7 +797,7 @@ mod tests {
}

let xml = r#"<foo><a attr1="12"/><c attr2="200"/></foo>"#;
let foo = xml_deserialize_from_str::<Foo>(&xml).unwrap();
let foo = xml_deserialize_from_str::<Foo>(xml).unwrap();
assert_eq!(foo.bar.a.attr1, 12);
assert_eq!(foo.bar.c.attr2, 200);

Expand All @@ -814,17 +808,18 @@ mod tests {
bar: Option<Bar>,
}
let xml = r#"<foo><a attr1="12"/><c attr2="200"/></foo>"#;
let foo = xml_deserialize_from_str::<FooOption>(&xml).unwrap();
let foo = xml_deserialize_from_str::<FooOption>(xml).unwrap();
let bar = foo.bar.unwrap();
assert_eq!(bar.a.attr1, 12);
assert_eq!(bar.c.attr2, 200);

let xml = r#"<foo>></foo>"#;
let foo = xml_deserialize_from_str::<FooOption>(&xml).unwrap();
let foo = xml_deserialize_from_str::<FooOption>(xml).unwrap();
assert!(foo.bar.is_none());
}

#[test]
#[allow(dead_code)]
fn test_issue_60() {
#[derive(Clone, Debug, Default, XmlDeserialize)]
pub struct Parameters {
Expand All @@ -839,6 +834,7 @@ mod tests {
}

#[test]
#[allow(dead_code)]
fn test_vec_deserialize() {
#[derive(Debug, XmlDeserialize)]
pub struct CtTextParagraph {
Expand Down Expand Up @@ -901,6 +897,38 @@ mod tests {
assert!(matches!(Status::default(), Status::Bird));
}

#[test]
fn test_unescape_xml_entities_in_attr() {
#[derive(Debug, XmlDeserialize)]
#[xmlserde(root = b"constant")]
struct Constant {
#[xmlserde(name = b"value", ty = "attr")]
value: String,
}

let xml = r#"<constant value="_-|&gt; &lt;."/>"#;
let c = xml_deserialize_from_str::<Constant>(xml).unwrap();
assert_eq!(c.value, "_-|> <.");

let xml = r#"<constant value="&amp;foo&apos;bar&quot;baz"/>"#;
let c = xml_deserialize_from_str::<Constant>(xml).unwrap();
assert_eq!(c.value, "&foo'bar\"baz");
}

#[test]
fn test_unescape_xml_entities_in_opt_attr() {
#[derive(Debug, XmlDeserialize)]
#[xmlserde(root = b"constant")]
struct Constant {
#[xmlserde(name = b"value", ty = "attr")]
value: Option<String>,
}

let xml = r#"<constant value="a &gt; b"/>"#;
let c = xml_deserialize_from_str::<Constant>(xml).unwrap();
assert_eq!(c.value.as_deref(), Some("a > b"));
}

pub fn default_one_u32() -> u32 {
1
}
Expand Down Expand Up @@ -953,7 +981,7 @@ mod tests {
PageFieldVal => "pageFieldVal",
}
}
let foo = xml_deserialize_from_str::<CtTableStyleElement>(&xml).unwrap();
let foo = xml_deserialize_from_str::<CtTableStyleElement>(xml).unwrap();
assert_eq!(foo.ty, StTableStyleType::WholeTable);
assert_eq!(foo.size, 1);
assert_eq!(foo.dxf_id, Some(6));
Expand Down
Loading