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
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "quick-xml"
version = "0.41.0"
version = "0.42.0"
description = "High performance xml reader and writer"
edition = "2021"
edition = "2024"

documentation = "https://docs.rs/quick-xml"
repository = "https://github.com/tafia/quick-xml"
Expand Down
16 changes: 14 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,24 @@

## Unreleased

### Breaking Changes

### New Features

### Bug Fixes

### Misc Changes


## 0.42.0 -- 2026-08-22
Comment thread
dralley marked this conversation as resolved.

This is a large release. The primary change is an ergonomic improvement across the entire API -
quick_xml now makes use of `&str` and `String` types where possible instead of
`&[u8]` and `Vec<u8>`. This requires significant refactoring of downstream code,
but should result in a net simplification as well as potential performance improvements.
but should result in a net simplification as well as potential performance improvements,
and opens up additional opportunities in future releases.

The MSRV has been raised to 1.86.
The MSRV has been raised to 1.86. We now use Rust 2024 Edition.

### Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion benches/encoding.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use pretty_assertions::assert_eq;

use std::io::{BufReader, Read};
Expand Down
2 changes: 1 addition & 1 deletion benches/issue971.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//! [#969]: https://github.com/tafia/quick-xml/issues/969
//! [#971]: https://github.com/tafia/quick-xml/pull/971

use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use quick_xml::events::Event;
use quick_xml::reader::Reader;

Expand Down
2 changes: 1 addition & 1 deletion benches/macrobenches.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use criterion::{self, criterion_group, criterion_main, Criterion, Throughput};
use criterion::{self, Criterion, Throughput, criterion_group, criterion_main};
use quick_xml::events::Event;
use quick_xml::reader::{NsReader, Reader};
use quick_xml::{Result as XmlResult, XmlVersion};
Expand Down
11 changes: 6 additions & 5 deletions benches/microbenches.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use criterion::{self, criterion_group, criterion_main, Criterion};
use criterion::{self, Criterion, criterion_group, criterion_main};
use pretty_assertions::assert_eq;
use quick_xml::escape::{escape, unescape};
use quick_xml::events::Event;
Expand Down Expand Up @@ -231,10 +231,11 @@ fn attributes(c: &mut Criterion) {
count += 1
}
}
assert!(e
.try_get_attribute("attribute-that-doesn't-exist")
.unwrap()
.is_none());
assert!(
e.try_get_attribute("attribute-that-doesn't-exist")
.unwrap()
.is_none()
);
}
Ok(Event::Eof) => break,
_ => (),
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
use std::borrow::Cow;
use std::collections::{HashMap, VecDeque};

use quick_xml::XmlVersion;
use quick_xml::errors::Error;
use quick_xml::escape::EscapeError;
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::name::QName;
use quick_xml::reader::Reader;
use quick_xml::XmlVersion;
use regex::Regex;

use pretty_assertions::assert_eq;
Expand Down
2 changes: 1 addition & 1 deletion examples/getting_started.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
//! - `writer.rs` for producing XML
//! - `examples/README.md` for a guide on which approach to choose

use quick_xml::XmlVersion;
use quick_xml::events::Event;
use quick_xml::reader::Reader;
use quick_xml::XmlVersion;

const XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<catalog>
Expand Down
2 changes: 1 addition & 1 deletion examples/read_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
// Note: for this specific data set using serde feature would simplify
// this simple data is purely to make it easier to understand the code

use quick_xml::XmlVersion;
use quick_xml::encoding::EncodingError;
use quick_xml::events::attributes::AttrError;
use quick_xml::events::{BytesStart, Event};
use quick_xml::name::QName;
use quick_xml::reader::Reader;
use quick_xml::XmlVersion;
use std::borrow::Cow;
use std::collections::HashMap;
use std::convert::Infallible;
Expand Down
2 changes: 1 addition & 1 deletion examples/read_utf16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ fn main() -> Result<(), quick_xml::Error> {
use std::fs::File;
use std::io::BufReader;

use quick_xml::XmlVersion;
use quick_xml::encoding::DecodingReader;
use quick_xml::events::Event;
use quick_xml::reader::Reader;
use quick_xml::XmlVersion;

let file = File::open("tests/documents/encoding/utf16le-bom.xml")?;
let transcoder = DecodingReader::new(BufReader::new(file));
Expand Down
2 changes: 1 addition & 1 deletion examples/reader_patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
//! cargo run --example reader_patterns
//! ```

use quick_xml::XmlVersion;
use quick_xml::events::{BytesStart, Event};
use quick_xml::reader::Reader;
use quick_xml::XmlVersion;

const XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<catalog>
Expand Down
5 changes: 5 additions & 0 deletions examples/serde_roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
//! |------------------------------|----------------------------------------------|
//! | attribute `id="..."` | `#[serde(rename = "@id")]` |
//! | text inside an element | `#[serde(rename = "$text")]` |
//! | xs:choice as Rust enum | `#[serde(rename = "$value")]` |
//! | fields shared across types | `#[serde(flatten)]` on a sub-struct |
//! | child element `<title>` | a field named `title` (no prefix) |
//! | repeated child elements | a `Vec<T>` field |
//! | the element's own tag name | chosen by the parent field / root, see below |
//!
//! See [`Mapping XML to Rust types`] for more info.
//!
//! Types are converted for you: `available="true"` becomes a `bool`,
//! `<price>39.95</price>` becomes an `f64`, and so on.
//!
Expand All @@ -28,6 +31,8 @@
//! ```console
//! cargo run --example serde_roundtrip --features serialize
//! ```
//!
//! [`Mapping XML to Rust types`]: https://docs.rs/quick-xml/latest/quick_xml/de/index.html#mapping-xml-to-rust-types

use quick_xml::de::from_str;
use quick_xml::events::{BytesEnd, BytesStart, Event};
Expand Down
2 changes: 1 addition & 1 deletion examples/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
//! cargo run --example visitor
//! ```

use quick_xml::XmlVersion;
use quick_xml::events::{BytesStart, Event};
use quick_xml::reader::Reader;
use quick_xml::XmlVersion;

const XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<catalog>
Expand Down
2 changes: 1 addition & 1 deletion fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "quick-xml-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2021"
edition = "2024"

[package.metadata]
cargo-fuzz = true
Expand Down
4 changes: 2 additions & 2 deletions src/de/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use std::borrow::Cow;
use serde::de::{DeserializeSeed, Deserializer, Error, MapAccess, Visitor};
use serde::forward_to_deserialize_any;

use crate::de::key::QNameDeserializer;
use crate::XmlVersion;
use crate::de::SimpleTypeDeserializer;
use crate::de::key::QNameDeserializer;
use crate::errors::serialize::DeError;
use crate::events::attributes::Attributes;
use crate::XmlVersion;

impl<'i> Attributes<'i> {
/// Converts this iterator into a serde's [`MapAccess`] trait to use with serde.
Expand Down
6 changes: 3 additions & 3 deletions src/de/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use crate::{
de::resolver::EntityResolver,
de::simple_type::SimpleTypeDeserializer,
de::text::TextDeserializer,
de::{DeEvent, Deserializer, XmlRead, TEXT_KEY, VALUE_KEY},
errors::serialize::DeError,
de::{DeEvent, Deserializer, TEXT_KEY, VALUE_KEY, XmlRead},
errors::Error,
events::attributes::IterState,
errors::serialize::DeError,
events::BytesStart,
events::attributes::IterState,
name::QName,
};
use serde::de::value::BorrowedStrDeserializer;
Expand Down
4 changes: 2 additions & 2 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2106,13 +2106,13 @@ mod var;
pub use self::attributes::AttributesDeserializer;
pub use self::resolver::{EntityResolver, PredefinedEntityResolver};
pub use self::simple_type::SimpleTypeDeserializer;
pub use crate::errors::serialize::DeError;
use crate::XmlVersion;
pub use crate::errors::serialize::DeError;

use crate::{
de::map::ElementMapAccess,
errors::Error,
escape::{parse_number, EscapeError},
escape::{EscapeError, parse_number},
events::{BytesCData, BytesEnd, BytesRef, BytesStart, BytesText, Event},
name::{NamespaceResolver, QName},
reader::{NsReader, Reader},
Expand Down
6 changes: 3 additions & 3 deletions src/de/simple_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
//! [simple types]: https://www.w3schools.com/xml/el_simpletype.asp
//! [as defined]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition

use crate::XmlVersion;
use crate::de::Text;
use crate::errors::serialize::DeError;
use crate::escape::resolve_predefined_entity;
use crate::utils::{trim_xml_spaces, CowRef};
use crate::XmlVersion;
use crate::utils::{CowRef, trim_xml_spaces};
use memchr::memchr;
use serde::de::value::UnitDeserializer;
use serde::de::{
Expand Down Expand Up @@ -741,8 +741,8 @@ impl<'de, 'a> IntoDeserializer<'de, DeError> for SimpleTypeDeserializer<'de, 'a>
#[cfg(test)]
mod tests {
use super::*;
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
use crate::se::QuoteLevel;
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
use crate::utils::{ByteBuf, Bytes};
use serde::de::IgnoredAny;
use serde::{Deserialize, Serialize};
Expand Down
2 changes: 1 addition & 1 deletion src/de/text.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
de::simple_type::SimpleTypeDeserializer,
de::{Text, TEXT_KEY},
de::{TEXT_KEY, Text},
errors::serialize::DeError,
};
use serde::de::value::BorrowedStrDeserializer;
Expand Down
2 changes: 1 addition & 1 deletion src/de/var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
de::map::ElementMapAccess,
de::resolver::EntityResolver,
de::simple_type::SimpleTypeDeserializer,
de::{DeEvent, Deserializer, XmlRead, TEXT_KEY},
de::{DeEvent, Deserializer, TEXT_KEY, XmlRead},
errors::serialize::DeError,
};
use serde::de::value::BorrowedStrDeserializer;
Expand Down
6 changes: 5 additions & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,11 @@ impl fmt::Display for IllFormedError {
f.write_str("an XML declaration does not contain `version` attribute")
}
Self::MissingDeclVersion(Some(attr)) => {
write!(f, "an XML declaration must start with `version` attribute, but in starts with `{}`", attr)
write!(
f,
"an XML declaration must start with `version` attribute, but in starts with `{}`",
attr
)
}
Self::UnknownVersion => {
f.write_str("unknown XML version: either 1.0 or 1.1 is expected")
Expand Down
22 changes: 11 additions & 11 deletions src/events/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
//!
//! Provides an iterator over attributes key/value pairs

use crate::XmlVersion;
use crate::encoding::Decoder;
use crate::errors::Result as XmlResult;
use crate::escape::{escape_attribute, resolve_predefined_entity};
use crate::name::{LocalName, Namespace, NamespaceResolver, QName};
use crate::utils::is_whitespace;
use crate::XmlVersion;

use std::collections::HashSet;
use std::fmt::{self, Debug, Display, Formatter};
Expand Down Expand Up @@ -967,7 +967,7 @@ impl IterState {
fn skip_value(&self, slice: &[u8], offset: usize) -> Option<usize> {
let mut iter = (offset..).zip(slice[offset..].iter());

match iter.find(|(_, &b)| is_whitespace(b)) {
match iter.find(|&(_, &b)| is_whitespace(b)) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From cargo fix --edition

// Input: ` key = value `
// | ^
// offset e
Expand All @@ -985,7 +985,7 @@ impl IterState {
let mut iter = (offset..).zip(slice[offset..].iter());

// Skip all up to the quote and get the quote type
let quote = match iter.find(|(_, &b)| !is_whitespace(b)) {
let quote = match iter.find(|&(_, &b)| !is_whitespace(b)) {
// Input: ` key = "`
// | ^
// offset
Expand All @@ -1005,7 +1005,7 @@ impl IterState {
None => return None,
};

match iter.find(|(_, &b)| b == quote) {
match iter.find(|&(_, &b)| b == quote) {
// Input: ` key = " "`
// ^
Some((e, b'"')) => Some(e),
Expand Down Expand Up @@ -1127,7 +1127,7 @@ impl IterState {
};

// Index where next key started
let start_key = match iter.find(|(_, &b)| !is_whitespace(b)) {
let start_key = match iter.find(|&(_, &b)| !is_whitespace(b)) {
// Input: ` key`
// ^
Some((s, _)) => s,
Expand All @@ -1140,15 +1140,15 @@ impl IterState {
}
};
// Span of a key
let (key, offset) = match iter.find(|(_, &b)| b == b'=' || is_whitespace(b)) {
let (key, offset) = match iter.find(|&(_, &b)| b == b'=' || is_whitespace(b)) {
// Input: ` key=`
// | ^
// s e
Some((e, b'=')) => (start_key..e, e),

// Input: ` key `
// ^
Some((e, _)) => match iter.find(|(_, &b)| !is_whitespace(b)) {
Some((e, _)) => match iter.find(|&(_, &b)| !is_whitespace(b)) {
// Input: ` key =`
// | | ^
// start_key e
Expand Down Expand Up @@ -1196,7 +1196,7 @@ impl IterState {
////////////////////////////////////////////////////////////////////////

// Gets the position of quote and quote type
let (start_value, quote) = match iter.find(|(_, &b)| !is_whitespace(b)) {
let (start_value, quote) = match iter.find(|&(_, &b)| !is_whitespace(b)) {
// Input: ` key = "`
// ^
Some((s, b'"')) => (s + 1, b'"'),
Expand All @@ -1211,7 +1211,7 @@ impl IterState {
// We do not check validity of attribute value characters as required
// according to https://html.spec.whatwg.org/#unquoted. It can be done
// during validation phase
let end = match iter.find(|(_, &b)| is_whitespace(b)) {
let end = match iter.find(|&(_, &b)| is_whitespace(b)) {
// Input: ` key = value `
// | ^
// s e
Expand Down Expand Up @@ -1240,7 +1240,7 @@ impl IterState {
}
};

match iter.find(|(_, &b)| b == quote) {
match iter.find(|&(_, &b)| b == quote) {
// Input: ` key = " "`
// ^
Some((e, b'"')) => self.double_q(key, start_value..e),
Expand Down Expand Up @@ -1296,9 +1296,9 @@ mod xml {

mod attribute_value_normalization {
use super::*;
use crate::XmlVersion::*;
use crate::errors::Error;
use crate::escape::EscapeError::*;
use crate::XmlVersion::*;
use pretty_assertions::assert_eq;

/// Empty values returned are unchanged
Expand Down
Loading
Loading