migrate quick-xml to 0.38

fixes #120
This commit is contained in:
Lennart
2025-09-05 15:24:34 +02:00
parent 87adf94947
commit 91586ee797
12 changed files with 81 additions and 47 deletions

4
Cargo.lock generated
View File

@@ -2599,9 +2599,9 @@ dependencies = [
[[package]] [[package]]
name = "quick-xml" name = "quick-xml"
version = "0.37.5" version = "0.38.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]

View File

@@ -62,7 +62,7 @@ tokio = { version = "1", features = [
url = "2.5" url = "2.5"
base64 = "0.22" base64 = "0.22"
thiserror = "2.0" thiserror = "2.0"
quick-xml = { version = "0.37" } quick-xml = { version = "0.38" }
rust-embed = "8.5" rust-embed = "8.5"
tower-sessions = "0.14" tower-sessions = "0.14"
futures-core = "0.3.31" futures-core = "0.3.31"

View File

@@ -66,6 +66,9 @@ impl<PN: XmlDeserialize> XmlDeserialize for PropElement<PN> {
Event::Text(_) | Event::CData(_) => { Event::Text(_) | Event::CData(_) => {
return Err(XmlError::UnsupportedEvent("Not expecting text here")); return Err(XmlError::UnsupportedEvent("Not expecting text here"));
} }
Event::GeneralRef(_) => {
return Err(::rustical_xml::XmlError::UnsupportedEvent("GeneralRef"));
}
Event::Decl(_) | Event::Comment(_) | Event::DocType(_) | Event::PI(_) => { /* ignore */ Event::Decl(_) | Event::Comment(_) | Event::DocType(_) | Event::PI(_) => { /* ignore */
} }
Event::End(_end) => { Event::End(_end) => {

View File

@@ -29,12 +29,9 @@ impl XmlSerialize for TagList {
}); });
let has_prefix = prefix.is_some(); let has_prefix = prefix.is_some();
let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
let qname = tagname
.as_ref()
.map(|tagname| ::quick_xml::name::QName(tagname.as_bytes()));
if let Some(qname) = &qname { if let Some(tagname) = tagname.as_ref() {
let mut bytes_start = BytesStart::from(qname.to_owned()); let mut bytes_start = BytesStart::new(tagname);
if !has_prefix && let Some(ns) = &ns { if !has_prefix && let Some(ns) = &ns {
bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
} }
@@ -49,8 +46,8 @@ impl XmlSerialize for TagList {
el.write_empty()?; el.write_empty()?;
} }
if let Some(qname) = &qname { if let Some(tagname) = tagname.as_ref() {
writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; writer.write_event(Event::End(BytesEnd::new(tagname)))?;
} }
Ok(()) Ok(())
} }

View File

@@ -34,12 +34,11 @@ impl Enum {
}); });
let has_prefix = prefix.is_some(); let has_prefix = prefix.is_some();
let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
let qname = tagname.as_ref().map(|tagname| ::quick_xml::name::QName(tagname.as_bytes()));
const enum_untagged: bool = #enum_untagged; const enum_untagged: bool = #enum_untagged;
if let Some(qname) = &qname { if let Some(tagname) = tagname.as_ref() {
let mut bytes_start = BytesStart::from(qname.to_owned()); let mut bytes_start = BytesStart::new(tagname);
if !has_prefix { if !has_prefix {
if let Some(ns) = &ns { if let Some(ns) = &ns {
bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
@@ -50,8 +49,8 @@ impl Enum {
#(#variant_serializers);* #(#variant_serializers);*
if let Some(qname) = &qname { if let Some(tagname) = tagname.as_ref() {
writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; writer.write_event(Event::End(BytesEnd::new(tagname)))?;
} }
Ok(()) Ok(())
} }

View File

@@ -66,6 +66,9 @@ impl Enum {
Event::CData(cdata) => { Event::CData(cdata) => {
return Err(::rustical_xml::XmlError::UnsupportedEvent("CDATA")); return Err(::rustical_xml::XmlError::UnsupportedEvent("CDATA"));
} }
Event::GeneralRef(_) => {
return Err(::rustical_xml::XmlError::UnsupportedEvent("GeneralRef"));
}
Event::Decl(_) => { /* <?xml ... ?> ignore this */ } Event::Decl(_) => { /* <?xml ... ?> ignore this */ }
Event::Comment(_) => { /* ignore */ } Event::Comment(_) => { /* ignore */ }
Event::DocType(_) => { /* ignore */ } Event::DocType(_) => { /* ignore */ }

View File

@@ -111,10 +111,9 @@ impl NamedStruct {
}); });
let has_prefix = prefix.is_some(); let has_prefix = prefix.is_some();
let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
let qname = tagname.as_ref().map(|tagname| ::quick_xml::name::QName(tagname.as_bytes()));
if let Some(qname) = &qname { if let Some(tagname) = tagname.as_ref() {
let mut bytes_start = BytesStart::from(qname.to_owned()); let mut bytes_start = BytesStart::new(tagname);
if !has_prefix { if !has_prefix {
if let Some(ns) = &ns { if let Some(ns) = &ns {
bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
@@ -133,8 +132,8 @@ impl NamedStruct {
} }
if !#is_empty { if !#is_empty {
#(#tag_writers);* #(#tag_writers);*
if let Some(qname) = &qname { if let Some(tagname) = tagname.as_ref() {
writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; writer.write_event(Event::End(BytesEnd::new(tagname)))?;
} }
} }
Ok(()) Ok(())

View File

@@ -148,6 +148,8 @@ impl NamedStruct {
} }
} }
let mut string = String::new();
if !empty { if !empty {
loop { loop {
let event = reader.read_event_into(&mut buf)?; let event = reader.read_event_into(&mut buf)?;
@@ -167,12 +169,23 @@ impl NamedStruct {
} }
} }
Event::Text(bytes_text) => { Event::Text(bytes_text) => {
let text = bytes_text.unescape()?; let text = bytes_text.decode()?;
#(#text_field_branches)* string.push_str(&text);
} }
Event::CData(cdata) => { Event::CData(cdata) => {
let text = String::from_utf8(cdata.to_vec())?; let text = String::from_utf8(cdata.to_vec())?;
#(#text_field_branches)* string.push_str(&text);
}
Event::GeneralRef(gref) => {
if let Some(char) = gref.resolve_char_ref()? {
string.push(char);
} else if let Some(text) =
quick_xml::escape::resolve_xml_entity(&gref.xml_content()?)
{
string.push_str(text);
} else {
return Err(XmlError::UnsupportedEvent("invalid XML ref"));
}
} }
Event::Decl(_) => { /* <?xml ... ?> ignore this */ } Event::Decl(_) => { /* <?xml ... ?> ignore this */ }
Event::Comment(_) => { /* ignore */ } Event::Comment(_) => { /* ignore */ }
@@ -185,6 +198,9 @@ impl NamedStruct {
} }
} }
let text = string;
#(#text_field_branches)*
Ok(Self { Ok(Self {
#(#builder_field_builds),* #(#builder_field_builds),*
}) })

View File

@@ -8,6 +8,8 @@ pub enum XmlError {
#[error(transparent)] #[error(transparent)]
QuickXmlError(#[from] quick_xml::Error), QuickXmlError(#[from] quick_xml::Error),
#[error(transparent)] #[error(transparent)]
QuickXmlEncodingError(#[from] quick_xml::encoding::EncodingError),
#[error(transparent)]
QuickXmlAttrError(#[from] quick_xml::events::attributes::AttrError), QuickXmlAttrError(#[from] quick_xml::events::attributes::AttrError),
#[error(transparent)] #[error(transparent)]
FromUtf8Error(#[from] FromUtf8Error), FromUtf8Error(#[from] FromUtf8Error),

View File

@@ -1,7 +1,7 @@
use crate::XmlRootTag; use crate::XmlRootTag;
use quick_xml::{ use quick_xml::{
events::{BytesStart, Event, attributes::Attribute}, events::{BytesStart, Event, attributes::Attribute},
name::{Namespace, QName}, name::Namespace,
}; };
use std::collections::HashMap; use std::collections::HashMap;
pub use xml_derive::XmlSerialize; pub use xml_derive::XmlSerialize;
@@ -76,9 +76,8 @@ impl XmlSerialize for () {
}); });
let has_prefix = prefix.is_some(); let has_prefix = prefix.is_some();
let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
let qname = tagname.as_ref().map(|tagname| QName(tagname.as_bytes())); if let Some(tagname) = tagname.as_ref() {
if let Some(qname) = &qname { let mut bytes_start = BytesStart::new(tagname);
let mut bytes_start = BytesStart::from(qname.to_owned());
if !has_prefix && let Some(ns) = &ns { if !has_prefix && let Some(ns) = &ns {
bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
} }

View File

@@ -1,6 +1,6 @@
use crate::{XmlDeserialize, XmlError, XmlSerialize}; use crate::{XmlDeserialize, XmlError, XmlSerialize};
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::name::{Namespace, QName}; use quick_xml::name::Namespace;
use std::collections::HashMap; use std::collections::HashMap;
use std::num::{ParseFloatError, ParseIntError}; use std::num::{ParseFloatError, ParseIntError};
use std::{convert::Infallible, io::BufRead}; use std::{convert::Infallible, io::BufRead};
@@ -77,20 +77,23 @@ impl<T: ValueDeserialize> XmlDeserialize for T {
loop { loop {
match reader.read_event_into(&mut buf)? { match reader.read_event_into(&mut buf)? {
Event::Text(bytes_text) => { Event::Text(bytes_text) => {
let text = bytes_text.unescape()?; let text = bytes_text.decode()?;
if !string.is_empty() { string.push_str(&text);
// Content already written
return Err(XmlError::UnsupportedEvent("content already written"));
}
string = text.to_string();
} }
Event::CData(cdata) => { Event::CData(cdata) => {
let text = String::from_utf8(cdata.to_vec())?; let text = String::from_utf8(cdata.to_vec())?;
if !string.is_empty() { string.push_str(&text);
// Content already written }
return Err(XmlError::UnsupportedEvent("content already written")); Event::GeneralRef(gref) => {
if let Some(char) = gref.resolve_char_ref()? {
string.push(char);
} else if let Some(text) =
quick_xml::escape::resolve_xml_entity(&gref.xml_content()?)
{
string.push_str(text);
} else {
return Err(XmlError::UnsupportedEvent("invalid XML ref"));
} }
string = text;
} }
Event::End(_) => break, Event::End(_) => break,
Event::Eof => return Err(XmlError::Eof), Event::Eof => return Err(XmlError::Eof),
@@ -123,17 +126,16 @@ impl<T: ValueSerialize> XmlSerialize for T {
}); });
let has_prefix = prefix.is_some(); let has_prefix = prefix.is_some();
let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
let qname = tagname.as_ref().map(|tagname| QName(tagname.as_bytes())); if let Some(tagname) = tagname.as_ref() {
if let Some(qname) = &qname { let mut bytes_start = BytesStart::new(tagname);
let mut bytes_start = BytesStart::from(qname.to_owned());
if !has_prefix && let Some(ns) = &ns { if !has_prefix && let Some(ns) = &ns {
bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
} }
writer.write_event(Event::Start(bytes_start))?; writer.write_event(Event::Start(bytes_start))?;
} }
writer.write_event(Event::Text(BytesText::new(&self.serialize())))?; writer.write_event(Event::Text(BytesText::new(&self.serialize())))?;
if let Some(qname) = &qname { if let Some(tagname) = tagname {
writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; writer.write_event(Event::End(BytesEnd::new(tagname)))?;
} }
Ok(()) Ok(())
} }

View File

@@ -275,7 +275,7 @@ fn test_xml_cdata() {
<document> <document>
<![CDATA[some text]]> <![CDATA[some text]]>
<href><![CDATA[some stuff]]></href> <href><![CDATA[some stuff]]></href>
<okay>&gt;</okay> <okay>nice&gt;text</okay>
</document> </document>
"#, "#,
) )
@@ -285,11 +285,25 @@ fn test_xml_cdata() {
Document { Document {
hello: "some text".to_owned(), hello: "some text".to_owned(),
href: "some stuff".to_owned(), href: "some stuff".to_owned(),
okay: ">".to_owned() okay: "nice>text".to_owned()
} }
); );
} }
#[test]
fn test_quickxml_bytesref() {
let gt = quick_xml::events::BytesRef::new("gt");
assert!(!gt.is_char_ref());
let result = if !gt.is_char_ref() {
quick_xml::escape::resolve_xml_entity(&gt.xml_content().unwrap())
.unwrap()
.to_string()
} else {
gt.xml_content().unwrap().to_string()
};
assert_eq!(result, ">");
}
#[test] #[test]
fn test_struct_xml_decl() { fn test_struct_xml_decl() {
#[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)] #[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)]
@@ -307,14 +321,14 @@ fn test_struct_xml_decl() {
let doc = Document::parse_str( let doc = Document::parse_str(
r#" r#"
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<document><child>Hello!</child></document>"#, <document><child>Hello!&amp;</child></document>"#,
) )
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
doc, doc,
Document { Document {
child: Child { child: Child {
text: "Hello!".to_owned() text: "Hello!&".to_owned()
} }
} }
); );