diff --git a/Cargo.toml b/Cargo.toml index bba4f9d..a87f8c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/derives/src/container.rs b/derives/src/container.rs index 569ac65..42542a6 100644 --- a/derives/src/container.rs +++ b/derives/src/container.rs @@ -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; diff --git a/derives/src/de.rs b/derives/src/de.rs index 87dde33..34b9524 100644 --- a/derives/src/de.rs +++ b/derives/src/de.rs @@ -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); @@ -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 @@ -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; @@ -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 } diff --git a/src/lib.rs b/src/lib.rs index efa7620..efe4033 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -168,9 +168,8 @@ pub trait XmlSerialize { impl XmlSerialize for Option { fn serialize(&self, tag: &[u8], writer: &mut quick_xml::Writer) { - match self { - Some(t) => t.serialize(tag, writer), - None => {} + if let Some(t) = self { + t.serialize(tag, writer) } } } @@ -178,7 +177,7 @@ impl XmlSerialize for Option { impl XmlSerialize for Vec { fn serialize(&self, _tag_: &[u8], _writer_: &mut quick_xml::Writer) { self.iter().for_each(|c| { - let _ = c.serialize(_tag_, _writer_); + c.serialize(_tag_, _writer_); }); } } @@ -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()); @@ -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)) } }); @@ -396,17 +398,13 @@ where let mut buf = Vec::::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!( diff --git a/tests/lib.rs b/tests/lib.rs index 26108ac..bfa0738 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -92,8 +92,8 @@ mod tests { let result = xml_deserialize_from_str::(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!(), @@ -429,7 +429,7 @@ mod tests { } let xml = r#"1999"#; - let p = xml_deserialize_from_str::(&xml).unwrap(); + let p = xml_deserialize_from_str::(xml).unwrap(); let ser = xml_serialize(p); assert_eq!(xml, ser); } @@ -462,7 +462,7 @@ mod tests { } let xml = r#""#; - let p = xml_deserialize_from_str::(&xml).unwrap(); + let p = xml_deserialize_from_str::(xml).unwrap(); match p.dummy { EnumA::A1(ref a) => assert_eq!(a.a_attr1, 3), EnumA::B1(_) => panic!(), @@ -499,7 +499,7 @@ mod tests { } let xml = r#""#; - let p = xml_deserialize_from_str::(&xml).unwrap(); + let p = xml_deserialize_from_str::(xml).unwrap(); assert_eq!(p.dummy.len(), 3); let ser = xml_serialize(p); assert_eq!(xml, &ser); @@ -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#""#; - let p = xml_deserialize_from_str::(&xml).unwrap(); - assert!(matches!(p.dummy, None)); + let p = xml_deserialize_from_str::(xml).unwrap(); + assert!(p.dummy.is_none()); let xml = r#""#; - let p = xml_deserialize_from_str::(&xml).unwrap(); + let p = xml_deserialize_from_str::(xml).unwrap(); match p.dummy { Some(EnumA::A1(ref a)) => assert_eq!(a.a_attr1, 3), None => panic!(), @@ -559,6 +553,7 @@ mod tests { } #[test] + #[allow(dead_code)] fn test_generics() { #[derive(Debug, XmlSerialize, XmlDeserialize)] #[xmlserde(root = b"Root")] @@ -570,7 +565,6 @@ mod tests { #[derive(XmlSerialize)] pub enum EnumB { #[xmlserde(name = b"a")] - #[allow(dead_code)] A1(T), } @@ -608,14 +602,14 @@ mod tests { } let xml = r#""#; - let p = xml_deserialize_from_str::(&xml).unwrap(); + let p = xml_deserialize_from_str::(xml).unwrap(); assert!(matches!(p.ty, ParameterType::VarArgs)); let expect = xml_serialize(p); assert_eq!(expect, ""); let xml = r#""#; - let p = xml_deserialize_from_str::(&xml).unwrap(); + let p = xml_deserialize_from_str::(xml).unwrap(); if let ParameterType::Type(t) = &p.ty { assert_eq!(t.name, "n") } else { @@ -625,7 +619,7 @@ mod tests { assert_eq!(expect, xml); let xml = r#"ttttt"#; - let p = xml_deserialize_from_str::(&xml).unwrap(); + let p = xml_deserialize_from_str::(xml).unwrap(); assert!(matches!(p.ty, ParameterType::Text(_))); let expect = xml_serialize(p); assert_eq!(expect, xml); @@ -658,10 +652,10 @@ mod tests { text1 text2 "#; - let text_p = xml_deserialize_from_str::(&xml).unwrap(); + let text_p = xml_deserialize_from_str::(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!("") @@ -679,10 +673,10 @@ mod tests { ); let xml = r#"abcdefg"#; - let text_p = xml_deserialize_from_str::(&xml).unwrap(); + let text_p = xml_deserialize_from_str::(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!("") @@ -702,7 +696,7 @@ mod tests { pub name: String, } let xml = r#""#; - let _ = xml_deserialize_from_str::(&xml).unwrap(); + let _ = xml_deserialize_from_str::(xml).unwrap(); } #[test] @@ -714,7 +708,7 @@ mod tests { pub name: String, } let xml = r#""#; - let _ = xml_deserialize_from_str::(&xml).unwrap(); + let _ = xml_deserialize_from_str::(xml).unwrap(); } #[test] @@ -728,7 +722,7 @@ mod tests { pub name: String, } let xml = r#""#; - let _ = xml_deserialize_from_str::(&xml).unwrap(); + let _ = xml_deserialize_from_str::(xml).unwrap(); } #[test] @@ -740,7 +734,7 @@ mod tests { pub name: String, } let xml = r#""#; - let _ = xml_deserialize_from_str::(&xml).unwrap(); + let _ = xml_deserialize_from_str::(xml).unwrap(); } // https://github.com/ImJeremyHe/xmlserde/issues/52 @@ -803,7 +797,7 @@ mod tests { } let xml = r#""#; - let foo = xml_deserialize_from_str::(&xml).unwrap(); + let foo = xml_deserialize_from_str::(xml).unwrap(); assert_eq!(foo.bar.a.attr1, 12); assert_eq!(foo.bar.c.attr2, 200); @@ -814,17 +808,18 @@ mod tests { bar: Option, } let xml = r#""#; - let foo = xml_deserialize_from_str::(&xml).unwrap(); + let foo = xml_deserialize_from_str::(xml).unwrap(); let bar = foo.bar.unwrap(); assert_eq!(bar.a.attr1, 12); assert_eq!(bar.c.attr2, 200); let xml = r#">"#; - let foo = xml_deserialize_from_str::(&xml).unwrap(); + let foo = xml_deserialize_from_str::(xml).unwrap(); assert!(foo.bar.is_none()); } #[test] + #[allow(dead_code)] fn test_issue_60() { #[derive(Clone, Debug, Default, XmlDeserialize)] pub struct Parameters { @@ -839,6 +834,7 @@ mod tests { } #[test] + #[allow(dead_code)] fn test_vec_deserialize() { #[derive(Debug, XmlDeserialize)] pub struct CtTextParagraph { @@ -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#""#; + let c = xml_deserialize_from_str::(xml).unwrap(); + assert_eq!(c.value, "_-|> <."); + + let xml = r#""#; + let c = xml_deserialize_from_str::(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, + } + + let xml = r#""#; + let c = xml_deserialize_from_str::(xml).unwrap(); + assert_eq!(c.value.as_deref(), Some("a > b")); + } + pub fn default_one_u32() -> u32 { 1 } @@ -953,7 +981,7 @@ mod tests { PageFieldVal => "pageFieldVal", } } - let foo = xml_deserialize_from_str::(&xml).unwrap(); + let foo = xml_deserialize_from_str::(xml).unwrap(); assert_eq!(foo.ty, StTableStyleType::WholeTable); assert_eq!(foo.size, 1); assert_eq!(foo.dxf_id, Some(6));