diff --git a/Cargo.lock b/Cargo.lock
index ea65934..6887174 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -875,6 +875,12 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "xml-rs"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
+
[[package]]
name = "xmlity"
version = "0.0.3"
@@ -908,6 +914,17 @@ dependencies = [
"xmlity",
]
+[[package]]
+name = "xmlity-xml-rs"
+version = "0.0.2"
+dependencies = [
+ "pretty_assertions",
+ "rstest",
+ "thiserror",
+ "xml-rs",
+ "xmlity",
+]
+
[[package]]
name = "yansi"
version = "1.0.1"
diff --git a/Cargo.toml b/Cargo.toml
index dc4a356..e820b94 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
-members = ["xmlity", "xmlity-derive", "xmlity-quick-xml"]
+members = ["xmlity", "xmlity-derive", "xmlity-quick-xml", "xmlity-xml-rs"]
[workspace.package]
version = "0.0.3"
diff --git a/xmlity-xml-rs/CHANGELOG.md b/xmlity-xml-rs/CHANGELOG.md
new file mode 100644
index 0000000..825c32f
--- /dev/null
+++ b/xmlity-xml-rs/CHANGELOG.md
@@ -0,0 +1 @@
+# Changelog
diff --git a/xmlity-xml-rs/Cargo.toml b/xmlity-xml-rs/Cargo.toml
new file mode 100644
index 0000000..b5dae4c
--- /dev/null
+++ b/xmlity-xml-rs/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "xmlity-xml-rs"
+description = "XMLity implementation of xml-rs."
+version = "0.0.2"
+edition.workspace = true
+rust-version.workspace = true
+authors.workspace = true
+documentation.workspace = true
+homepage.workspace = true
+repository.workspace = true
+license.workspace = true
+exclude.workspace = true
+
+[dependencies]
+thiserror.workspace = true
+xmlity.workspace = true
+xml-rs = "0.8.26"
+
+
+[dev-dependencies]
+pretty_assertions.workspace = true
+rstest.workspace = true
+xmlity = { workspace = true, features = ["derive"] }
diff --git a/xmlity-xml-rs/README.md b/xmlity-xml-rs/README.md
new file mode 100644
index 0000000..0132df8
--- /dev/null
+++ b/xmlity-xml-rs/README.md
@@ -0,0 +1,27 @@
+# # XMLity xml-rs [![Build Status]][actions] [![Latest Version]][crates.io] [![Latest Docs]][docs.rs] [![xmlity msrv]][Rust 1.82]
+
+[Build Status]: https://img.shields.io/github/actions/workflow/status/lukasfri/xmlity/rust.yaml?branch=main
+[actions]: https://github.com/lukasfri/xmlity/actions?query=branch%3Amain
+[Latest Version]: https://img.shields.io/crates/v/xmlity-quick-xml.svg
+[crates.io]: https://crates.io/crates/xmlity-quick-xml
+[Latest Docs]: https://img.shields.io/badge/docs.rs-Latest-bbbbbb.svg
+[docs.rs]: https://docs.rs/xmlity-quick-xml/latest/xmlity_quick_xml
+[xmlity msrv]: https://img.shields.io/badge/rustc-1.82.0+-ab6000.svg
+[Rust 1.82]: https://blog.rust-lang.org/2023/06/01/Rust-1.82.0.html
+
+This crate contains the implementation of the [`xml-rs`] backend for XMLity. It is the intention to keep this crate up to date with the latest version of `xml-rs` and `xmlity`.
+
+## License
+
+
+Licensed under either of Apache License, Version
+2.0 or MIT license at your option.
+
+
+
+
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
+
diff --git a/xmlity-xml-rs/src/de.rs b/xmlity-xml-rs/src/de.rs
new file mode 100644
index 0000000..c0fc65b
--- /dev/null
+++ b/xmlity-xml-rs/src/de.rs
@@ -0,0 +1,752 @@
+use std::{io::Read, ops::Deref};
+
+use xml::{
+ attribute::OwnedAttribute,
+ name::OwnedName,
+ reader::{EventReader, XmlEvent},
+};
+
+use xmlity::{
+ de::{self, Error as _, Unexpected, Visitor},
+ Deserialize, ExpandedName, QName, XmlNamespace,
+};
+
+use crate::{IsExpandedName, IsQName};
+
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error("Quick XML error: {0}")]
+ XmlRs(#[from] xml::reader::Error),
+ #[error("IO error: {0}")]
+ Io(#[from] std::io::Error),
+ #[error("Unexpected: {0}")]
+ Unexpected(xmlity::de::Unexpected),
+ #[error("Custom: {0}")]
+ Custom(String),
+ #[error("Wrong name: expected {expected:?}, got {actual:?}")]
+ WrongName {
+ actual: Box>,
+ expected: Box>,
+ },
+ #[error("Unknown child")]
+ UnknownChild,
+ #[error("Invalid UTF-8: {0}")]
+ InvalidUtf8(#[from] std::string::FromUtf8Error),
+ #[error("Invalid string")]
+ InvalidString,
+ #[error("Missing field: {field}")]
+ MissingField { field: String },
+ #[error("No possible variant: {ident}")]
+ NoPossibleVariant { ident: String },
+ #[error("Missing data")]
+ MissingData,
+}
+
+impl xmlity::de::Error for Error {
+ fn custom(msg: T) -> Self {
+ Error::Custom(msg.to_string())
+ }
+
+ fn wrong_name(actual: &ExpandedName<'_>, expected: &ExpandedName<'_>) -> Self {
+ Error::WrongName {
+ actual: Box::new(actual.clone().into_owned()),
+ expected: Box::new(expected.clone().into_owned()),
+ }
+ }
+
+ fn unexpected_visit(unexpected: xmlity::de::Unexpected, _expected: &T) -> Self {
+ Error::Unexpected(unexpected)
+ }
+
+ fn missing_field(field: &str) -> Self {
+ Error::MissingField {
+ field: field.to_string(),
+ }
+ }
+
+ fn no_possible_variant(ident: &str) -> Self {
+ Error::NoPossibleVariant {
+ ident: ident.to_string(),
+ }
+ }
+
+ fn missing_data() -> Self {
+ Error::MissingData
+ }
+
+ fn unknown_child() -> Self {
+ Error::UnknownChild
+ }
+
+ fn invalid_string() -> Self {
+ Error::InvalidString
+ }
+}
+
+pub enum Peeked<'a> {
+ None,
+ Text,
+ CData,
+ Element {
+ name: QName<'a>,
+ namespace: Option>,
+ },
+}
+
+pub struct Deserializer {
+ reader: EventReader,
+ current_depth: i16,
+ peeked_event: Option,
+}
+
+impl From> for Deserializer {
+ fn from(reader: EventReader) -> Self {
+ Self::new(reader)
+ }
+}
+
+impl Deserializer {
+ pub fn new(reader: EventReader) -> Self {
+ Self {
+ reader,
+ current_depth: 0,
+ peeked_event: None,
+ }
+ }
+
+ fn read_event(&mut self) -> Result