Skip to content

Commit

Permalink
Port from xml-rs to quick-xml
Browse files Browse the repository at this point in the history
Co-authored-by: max <[email protected]>
  • Loading branch information
jcgruenhage and pr2502 committed Nov 17, 2022
1 parent 32103bf commit 147a4f6
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 243 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ base64 = "0.13.0"
time = { version = "0.3.3", features = ["parsing", "formatting"] }
indexmap = "1.0.2"
line-wrap = "0.1.1"
xml_rs = { package = "xml-rs", version = "0.8.2" }
quick_xml = { package = "quick-xml", version = "0.22.0" }
serde = { version = "1.0.2", optional = true }

[dev-dependencies]
Expand Down
19 changes: 4 additions & 15 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ pub(crate) enum ErrorKind {

// Xml format-specific errors
UnclosedXmlElement,
UnpairedXmlClosingTag,
UnexpectedXmlCharactersExpectedElement,
UnexpectedXmlOpeningTag,
UnknownXmlElement,
Expand Down Expand Up @@ -61,11 +60,8 @@ pub(crate) enum ErrorKind {
Serde(String),
}

#[derive(Debug)]
pub(crate) enum FilePosition {
LineColumn(u64, u64),
Offset(u64),
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct FilePosition(pub(crate) u64);

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(crate) enum EventKind {
Expand Down Expand Up @@ -141,14 +137,7 @@ impl fmt::Display for Error {

impl fmt::Display for FilePosition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FilePosition::LineColumn(line, column) => {
write!(f, "line {}, column {}", line, column)
}
FilePosition::Offset(offset) => {
write!(f, "offset {}", offset)
}
}
write!(f, "offset {}", self.0)
}
}

Expand All @@ -160,7 +149,7 @@ impl From<InvalidXmlDate> for Error {

impl ErrorKind {
pub fn with_byte_offset(self, offset: u64) -> Error {
self.with_position(FilePosition::Offset(offset))
self.with_position(FilePosition(offset))
}

pub fn with_position(self, pos: FilePosition) -> Error {
Expand Down
32 changes: 31 additions & 1 deletion src/serde_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,9 @@ fn dictionary_serialize_xml() {
\t\t<key>FirstKey</key>
\t\t<string>FirstValue</string>
\t\t<key>SecondKey</key>
\t\t<data>\n\t\tChQeKA==\n\t\t</data>
\t\t<data>
\t\tChQeKA==
\t\t</data>
\t\t<key>ThirdKey</key>
\t\t<real>1.234</real>
\t\t<key>FourthKey</key>
Expand All @@ -880,6 +882,34 @@ fn dictionary_serialize_xml() {
assert_eq!(xml, comparison);
}

#[test]
fn empty_array_and_dictionary_serialize_to_xml() {
#[derive(Serialize, Default)]
struct Empty {
vec: Vec<String>,
map: BTreeMap<String, String>,
}

// Serialize dictionary as an XML plist.
let mut buf = Cursor::new(Vec::new());
crate::to_writer_xml(&mut buf, &Empty::default()).unwrap();
let buf = buf.into_inner();
let xml = std::str::from_utf8(&buf).unwrap();

let comparison = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
\t<key>vec</key>
\t<array/>
\t<key>map</key>
\t<dict/>
</dict>
</plist>";

assert_eq!(xml, comparison);
}

#[test]
fn serde_yaml_to_value() {
let value: Value = serde_yaml::from_str("true").unwrap();
Expand Down
40 changes: 36 additions & 4 deletions src/stream/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ enum StackItem<'a> {
/// Options for customizing serialization of XML plists.
#[derive(Clone, Debug)]
pub struct XmlWriteOptions {
indent_str: Cow<'static, str>,
root_element: bool,
indent_char: u8,
indent_amount: usize,
}

impl XmlWriteOptions {
Expand All @@ -96,8 +97,38 @@ impl XmlWriteOptions {
/// This may be either an `&'static str` or an owned `String`.
///
/// The default is `\t`.
pub fn indent_string(mut self, indent_str: impl Into<Cow<'static, str>>) -> Self {
self.indent_str = indent_str.into();
///
/// Since replacing `xml-rs` with `quick-xml`, the indent string has to consist of a single
/// repeating ascii character. This is a backwards compatibility function, prefer using
/// `XmlWriteOptions::with_indent`.
#[deprecated(since="1.4.0", note="please use `with_indent` instead")]
pub fn indent_string(self, indent_str: impl Into<Cow<'static, str>>) -> Self {
let indent_str = indent_str.into();
let indent_str = indent_str.as_ref();

if indent_str.is_empty() {
return self.with_indent(0, 0);
}

assert!(
indent_str.chars().all(|chr| chr.is_ascii()),
"indent str must be ascii"
);
let indent_str = indent_str.as_bytes();
assert!(
indent_str.iter().all(|chr| chr == &indent_str[0]),
"indent str must consist of a single repeating character"
);

self.with_indent(indent_str[0], indent_str.len())
}

/// Specifies the character and amount used for indentation.
///
/// The default is indenting with a single tab.
pub fn with_indent(mut self, indent_char: u8, indent_amount: usize) -> Self {
self.indent_char = indent_char;
self.indent_amount = indent_amount;
self
}

Expand All @@ -122,7 +153,8 @@ impl XmlWriteOptions {
impl Default for XmlWriteOptions {
fn default() -> Self {
XmlWriteOptions {
indent_str: Cow::Borrowed("\t"),
indent_char: b'\t',
indent_amount: 1,
root_element: true,
}
}
Expand Down
Loading

0 comments on commit 147a4f6

Please sign in to comment.