use core::str;
use std::borrow::{Borrow, Cow};
use std::collections::BTreeMap;
use std::io::Write;
use std::ops::DerefMut;
use quick_xml::events::{BytesCData, BytesDecl, BytesEnd, BytesPI, BytesStart, BytesText, Event};
use quick_xml::writer::Writer as QuickXmlWriter;
use xmlity::{
ser::{self, Error as _, IncludePrefix, Unexpected},
ExpandedName, Prefix, QName, Serialize, XmlNamespace,
};
use xmlity::{ExpandedNameBuf, NoopDeSerializer, PrefixBuf, QNameBuf, XmlNamespaceBuf};
use crate::{OwnedQuickName, XmlnsDeclaration};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Quick XML error: {0}")]
QuickXml(#[from] quick_xml::Error),
#[error("Attribute error: {0}")]
AttrError(#[from] quick_xml::events::attributes::AttrError),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Custom: {0}")]
Custom(String),
#[error("Invalid UTF-8: {0}")]
InvalidUtf8(#[from] std::string::FromUtf8Error),
}
impl xmlity::ser::Error for Error {
fn unexpected_serialize(unexpected: ser::Unexpected) -> Self {
Error::Custom(format!("Unexpected serialize: {unexpected:?}"))
}
fn custom<T: ToString>(msg: T) -> Self {
Error::Custom(msg.to_string())
}
}
fn serializer_to_string<T>(serializer: QuickXmlWriter<Vec<u8>>, value: &T) -> Result<String, Error>
where
T: Serialize,
{
let mut serializer = Serializer::from(serializer);
value.serialize(&mut serializer)?;
let bytes = serializer.into_inner();
String::from_utf8(bytes).map_err(Error::InvalidUtf8)
}
pub fn to_string<T>(value: &T) -> Result<String, Error>
where
T: Serialize,
{
serializer_to_string(QuickXmlWriter::new(Vec::new()), value)
}
pub fn to_string_pretty<T>(value: &T, indentation: usize) -> Result<String, Error>
where
T: Serialize,
{
serializer_to_string(
QuickXmlWriter::new_with_indent(Vec::new(), b' ', indentation),
value,
)
}
struct NamespaceScope {
pub defined_namespaces: BTreeMap<Cow<'static, Prefix>, Cow<'static, XmlNamespace>>,
}
impl NamespaceScope {
pub fn new() -> Self {
Self {
defined_namespaces: BTreeMap::new(),
}
}
const XML_PREFIX: &'static Prefix = unsafe { Prefix::new_unchecked("xml") };
const XML_NAMESPACE: &'static XmlNamespace =
unsafe { XmlNamespace::new_unchecked("http://www.w3.org/XML/1998/namespace") };
pub fn top_scope() -> Self {
let mut scope = Self::new();
scope.defined_namespaces.insert(
Cow::Borrowed(Self::XML_PREFIX),
Cow::Borrowed(Self::XML_NAMESPACE),
);
scope
}
pub fn get_namespace<'b>(&'b self, prefix: &'b Prefix) -> Option<&'b XmlNamespace> {
self.defined_namespaces.get(prefix).map(|v| &**v)
}
}
struct NamespaceScopeContainer {
scopes: Vec<NamespaceScope>,
prefix_generator: PrefixGenerator,
}
struct PrefixGenerator {
count: usize,
}
impl PrefixGenerator {
pub fn index_to_name(index: usize) -> PrefixBuf {
let letter = (index / 26) as u8 + b'a';
let number = (index % 26) as u8 + b'0';
let mut name = String::with_capacity(2);
name.push(letter as char);
name.push(number as char);
PrefixBuf::new(name).expect("Invalid prefix generated")
}
pub fn new() -> Self {
Self { count: 0 }
}
pub fn new_prefix(&mut self) -> PrefixBuf {
let name = Self::index_to_name(self.count);
self.count += 1;
name
}
}
impl NamespaceScopeContainer {
pub fn new() -> Self {
Self {
scopes: vec![NamespaceScope::top_scope()],
prefix_generator: PrefixGenerator::new(),
}
}
pub fn push_scope(&mut self) {
self.scopes.push(NamespaceScope::new())
}
pub fn pop_scope(&mut self) -> Option<NamespaceScope> {
self.scopes.pop()
}
pub fn get_namespace<'b>(&'b self, prefix: &'b Prefix) -> Option<&'b XmlNamespace> {
self.scopes
.iter()
.rev()
.find_map(|a| a.get_namespace(prefix))
}
pub fn find_matching_namespace<'b>(&'b self, namespace: &XmlNamespace) -> Option<&'b Prefix> {
self.scopes.iter().rev().find_map(|a| {
a.defined_namespaces
.iter()
.find(|(_, found_namespace)| *namespace == ***found_namespace)
.map(|(prefix, _)| &**prefix)
})
}
pub fn resolve_namespace<'b>(
&'b mut self,
namespace: &'_ XmlNamespace,
preferred_prefix: Option<&Prefix>,
always_declare: IncludePrefix,
) -> (&'b Prefix, Option<XmlnsDeclaration<'b>>) {
if always_declare != IncludePrefix::Always {
let existing_prefix = self.find_matching_namespace(namespace);
if let Some(existing_prefix) = existing_prefix {
if (always_declare == IncludePrefix::WhenNecessaryForPreferredPrefix
&& preferred_prefix
.is_none_or(|preferred_prefix| preferred_prefix == existing_prefix))
|| always_declare == IncludePrefix::Never
{
let existing_prefix = self.find_matching_namespace(namespace).unwrap();
return (existing_prefix, None);
}
}
}
let prefix = preferred_prefix
.filter(|p| self.get_namespace(p).is_none_or(|n| n == namespace))
.or_else(|| {
preferred_prefix
.filter(|p| self.get_namespace(p).is_none_or(|n| n == namespace))
})
.map(|p| p.to_owned())
.unwrap_or_else(|| self.prefix_generator.new_prefix());
let scope = self
.scopes
.last_mut()
.expect("There should be at least one scope");
scope
.defined_namespaces
.insert(Cow::Owned(prefix.clone()), Cow::Owned(namespace.to_owned()));
let (prefix, namespace) = scope
.defined_namespaces
.get_key_value(Borrow::<Prefix>::borrow(&prefix))
.expect("The namespace should be defined as it was just added");
let xmlns = XmlnsDeclaration::new(prefix.as_ref(), namespace.as_ref());
(prefix.as_ref(), Some(xmlns))
}
pub fn resolve_name<'a>(
&'a mut self,
local_name: ExpandedName<'a>,
preferred_prefix: Option<&'a Prefix>,
always_declare: IncludePrefix,
) -> (QName<'a>, Option<XmlnsDeclaration<'a>>) {
let (local_name, namespace) = local_name.into_parts();
let (prefix, declaration) = namespace
.as_ref()
.map(|namespace| self.resolve_namespace(namespace, preferred_prefix, always_declare))
.unzip();
let declaration = declaration.flatten();
let name = QName::new(prefix, local_name);
(name, declaration)
}
}
pub struct Serializer<W: Write> {
writer: QuickXmlWriter<W>,
preferred_namespace_prefixes: BTreeMap<XmlNamespaceBuf, PrefixBuf>,
namespace_scopes: NamespaceScopeContainer,
buffered_bytes_start: BytesStart<'static>,
buffered_bytes_start_empty: bool,
}
impl<W: Write> Serializer<W> {
pub fn new(writer: QuickXmlWriter<W>) -> Self {
Self::new_with_namespaces(writer, BTreeMap::new())
}
pub fn new_with_namespaces(
writer: QuickXmlWriter<W>,
preferred_namespace_prefixes: BTreeMap<XmlNamespaceBuf, PrefixBuf>,
) -> Self {
Self {
writer,
preferred_namespace_prefixes,
namespace_scopes: NamespaceScopeContainer::new(),
buffered_bytes_start: BytesStart::new(""),
buffered_bytes_start_empty: true,
}
}
pub fn into_inner(self) -> W {
self.writer.into_inner()
}
fn push_namespace_scope(&mut self) {
self.namespace_scopes.push_scope()
}
fn pop_namespace_scope(&mut self) {
self.namespace_scopes.pop_scope();
}
}
impl<W: Write> From<QuickXmlWriter<W>> for Serializer<W> {
fn from(writer: QuickXmlWriter<W>) -> Self {
Self::new(writer)
}
}
impl<W: Write> From<W> for Serializer<W> {
fn from(writer: W) -> Self {
Self::new(QuickXmlWriter::new(writer))
}
}
pub struct SerializeElement<'s, W: Write> {
serializer: &'s mut Serializer<W>,
name: ExpandedNameBuf,
include_prefix: IncludePrefix,
preferred_prefix: Option<PrefixBuf>,
}
pub struct AttributeSerializer<'t, W: Write> {
name: ExpandedNameBuf,
serializer: &'t mut Serializer<W>,
preferred_prefix: Option<PrefixBuf>,
enforce_prefix: IncludePrefix,
}
pub struct TextSerializer {
value: Option<String>,
}
impl ser::SerializeSeq for &mut TextSerializer {
type Ok = ();
type Error = Error;
fn serialize_element<V: Serialize>(&mut self, value: &V) -> Result<Self::Ok, Self::Error> {
if self.value.is_some() {
return Err(Error::unexpected_serialize(Unexpected::Text));
}
let mut text_ser = TextSerializer { value: None };
value.serialize(&mut text_ser)?;
if let Some(value) = text_ser.value {
self.value = Some(value);
} else {
return Err(Error::unexpected_serialize(Unexpected::None));
}
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<'a> ser::Serializer for &'a mut TextSerializer {
type Ok = ();
type Error = Error;
type SerializeElement = NoopDeSerializer<Self::Ok, Self::Error>;
type SerializeSeq = &'a mut TextSerializer;
fn serialize_text<S: AsRef<str>>(self, text: S) -> Result<(), Self::Error> {
if self.value.is_some() {
return Err(Error::unexpected_serialize(Unexpected::Text));
}
self.value = Some(text.as_ref().to_string());
Ok(())
}
fn serialize_cdata<S: AsRef<str>>(self, text: S) -> Result<Self::Ok, Self::Error> {
let _ = text;
Err(Error::unexpected_serialize(Unexpected::CData))
}
fn serialize_element(
self,
name: &'_ ExpandedName<'_>,
) -> Result<Self::SerializeElement, Self::Error> {
let _ = name;
Err(Error::unexpected_serialize(Unexpected::Element))
}
fn serialize_seq(self) -> Result<Self::SerializeSeq, Self::Error> {
Ok(self)
}
fn serialize_decl<S: AsRef<str>>(
self,
version: S,
encoding: Option<S>,
standalone: Option<S>,
) -> Result<Self::Ok, Self::Error> {
let _ = (version, encoding, standalone);
Err(Error::unexpected_serialize(Unexpected::Decl))
}
fn serialize_pi<S: AsRef<[u8]>>(self, target: S, content: S) -> Result<Self::Ok, Self::Error> {
let _ = (target, content);
Err(Error::unexpected_serialize(Unexpected::PI))
}
fn serialize_comment<S: AsRef<[u8]>>(self, text: S) -> Result<Self::Ok, Self::Error> {
let _ = text;
Err(Error::unexpected_serialize(Unexpected::Comment))
}
fn serialize_doctype<S: AsRef<[u8]>>(self, text: S) -> Result<Self::Ok, Self::Error> {
let _ = text;
Err(Error::unexpected_serialize(Unexpected::DocType))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(Error::unexpected_serialize(Unexpected::None))
}
}
impl<W: Write> ser::SerializeAttributeAccess for AttributeSerializer<'_, W> {
type Ok = ();
type Error = Error;
fn include_prefix(&mut self, should_enforce: IncludePrefix) -> Result<Self::Ok, Self::Error> {
self.enforce_prefix = should_enforce;
Ok(())
}
fn preferred_prefix(
&mut self,
preferred_prefix: Option<&Prefix>,
) -> Result<Self::Ok, Self::Error> {
self.preferred_prefix = preferred_prefix.map(Prefix::to_owned);
Ok(())
}
fn end<S: Serialize>(self, value: &S) -> Result<Self::Ok, Self::Error> {
let preferred_prefix = self.preferred_prefix.as_deref().or_else(|| {
self.name
.namespace()
.and_then(|a| self.serializer.preferred_namespace_prefixes.get(a))
.map(|p| &**p)
});
let (qname, decl) = self.serializer.namespace_scopes.resolve_name(
self.name.as_ref(),
preferred_prefix,
self.enforce_prefix,
);
if let Some(decl) = decl {
self.serializer.buffered_bytes_start.push_declaration(decl);
}
let mut text_ser = TextSerializer { value: None };
value.serialize(&mut text_ser)?;
self.serializer.buffered_bytes_start.push_attribute_xmlity(
qname,
Cow::Owned(
text_ser
.value
.expect("TextSerializer should have a value")
.into_bytes(),
),
);
Ok(())
}
}
impl<W: Write> ser::AttributeSerializer for &mut SerializeElementAttributes<'_, W> {
type Error = Error;
type Ok = ();
type SerializeAttribute<'a>
= AttributeSerializer<'a, W>
where
Self: 'a;
fn serialize_attribute(
&mut self,
name: &'_ ExpandedName,
) -> Result<Self::SerializeAttribute<'_>, Self::Error> {
Ok(Self::SerializeAttribute {
name: name.into_owned(),
serializer: self.serializer.deref_mut(),
preferred_prefix: None,
enforce_prefix: IncludePrefix::default(),
})
}
fn serialize_none(&mut self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
impl<'s, W: Write> SerializeElement<'s, W> {
fn finish_start(self) -> (QNameBuf, &'s mut Serializer<W>) {
let Self {
name,
include_prefix,
preferred_prefix,
serializer,
} = self;
assert!(
serializer.buffered_bytes_start_empty,
"Should have been emptied by the serializer"
);
serializer.buffered_bytes_start.clear_attributes();
let preferred_prefix = preferred_prefix.as_deref().or_else(|| {
name.as_ref()
.namespace()
.and_then(|a| serializer.preferred_namespace_prefixes.get(a))
.map(|p| &**p)
});
let (qname, decl) = serializer.namespace_scopes.resolve_name(
name.as_ref(),
preferred_prefix,
include_prefix,
);
let qname = qname.into_owned();
serializer
.buffered_bytes_start
.set_name(qname.to_string().as_bytes());
if let Some(decl) = decl {
serializer.buffered_bytes_start.push_declaration(decl);
}
serializer.buffered_bytes_start_empty = false;
(qname, serializer)
}
fn end_empty(serializer: &mut Serializer<W>) -> Result<(), Error> {
assert!(
!serializer.buffered_bytes_start_empty,
"start should be buffered"
);
let start = serializer.buffered_bytes_start.borrow();
serializer
.writer
.write_event(Event::Empty(start))
.map_err(Error::Io)?;
serializer.buffered_bytes_start_empty = true;
Ok(())
}
}
pub struct SerializeElementAttributes<'s, W: Write> {
serializer: &'s mut Serializer<W>,
end_name: QNameBuf,
}
impl<W: Write> ser::SerializeAttributes for SerializeElementAttributes<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_attribute<A: ser::SerializeAttribute>(
&mut self,
a: &A,
) -> Result<Self::Ok, Self::Error> {
a.serialize_attribute(self)
}
}
impl<'s, W: Write> ser::SerializeElementAttributes for SerializeElementAttributes<'s, W> {
type ChildrenSerializeSeq = ChildrenSerializeSeq<'s, W>;
fn serialize_children(self) -> Result<Self::ChildrenSerializeSeq, Self::Error> {
Ok(ChildrenSerializeSeq {
serializer: self.serializer,
end_name: self.end_name,
})
}
fn end(self) -> Result<Self::Ok, Self::Error> {
SerializeElement::end_empty(self.serializer)
}
}
impl<'s, W: Write> ser::SerializeElement for SerializeElement<'s, W> {
type Ok = ();
type Error = Error;
type ChildrenSerializeSeq = ChildrenSerializeSeq<'s, W>;
type SerializeElementAttributes = SerializeElementAttributes<'s, W>;
fn include_prefix(&mut self, should_enforce: IncludePrefix) -> Result<Self::Ok, Self::Error> {
self.include_prefix = should_enforce;
Ok(())
}
fn preferred_prefix(
&mut self,
preferred_prefix: Option<&Prefix>,
) -> Result<Self::Ok, Self::Error> {
self.preferred_prefix = preferred_prefix.map(Prefix::to_owned);
Ok(())
}
fn serialize_attributes(self) -> Result<Self::SerializeElementAttributes, Self::Error> {
self.serializer.push_namespace_scope();
let (end_name, serializer) = self.finish_start();
Ok(SerializeElementAttributes {
serializer,
end_name,
})
}
fn serialize_children(self) -> Result<Self::ChildrenSerializeSeq, Self::Error> {
self.serializer.push_namespace_scope();
let (end_name, serializer) = self.finish_start();
Ok(ChildrenSerializeSeq {
serializer,
end_name,
})
}
fn end(self) -> Result<Self::Ok, Self::Error> {
self.serializer.push_namespace_scope();
let (_, serializer) = self.finish_start();
SerializeElement::end_empty(serializer)?;
serializer.pop_namespace_scope();
Ok(())
}
}
pub struct ChildrenSerializeSeq<'s, W: Write> {
serializer: &'s mut Serializer<W>,
end_name: QNameBuf,
}
impl<W: Write> ser::SerializeSeq for ChildrenSerializeSeq<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_element<V: Serialize>(&mut self, value: &V) -> Result<(), Self::Error> {
value.serialize(self.serializer.deref_mut())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
if !self.serializer.buffered_bytes_start_empty {
self.serializer
.writer
.write_event(Event::Empty(self.serializer.buffered_bytes_start.borrow()))
.map_err(Error::Io)?;
self.serializer.buffered_bytes_start_empty = true;
} else {
let end_name = OwnedQuickName::new(&self.end_name.as_ref());
let bytes_end = BytesEnd::from(end_name.as_ref());
self.serializer
.writer
.write_event(Event::End(bytes_end))
.map_err(Error::Io)?;
}
self.serializer.pop_namespace_scope();
Ok(())
}
}
pub struct SerializeSeq<'e, W: Write> {
serializer: &'e mut Serializer<W>,
}
impl<W: Write> ser::SerializeSeq for SerializeSeq<'_, W> {
type Ok = ();
type Error = Error;
fn serialize_element<V: Serialize>(&mut self, v: &V) -> Result<(), Self::Error> {
v.serialize(self.serializer.deref_mut())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
trait BytesStartExt<'a> {
fn push_attribute_xmlity(&mut self, qname: QName<'_>, value: Cow<'a, [u8]>);
fn push_declaration(&mut self, decl: XmlnsDeclaration<'_>);
}
impl<'a> BytesStartExt<'a> for BytesStart<'a> {
fn push_attribute_xmlity(&mut self, qname: QName<'_>, value: Cow<'a, [u8]>) {
self.push_attribute(quick_xml::events::attributes::Attribute {
key: quick_xml::name::QName(qname.to_string().as_bytes()),
value,
});
}
fn push_declaration(&mut self, decl: XmlnsDeclaration<'_>) {
let XmlnsDeclaration { namespace, prefix } = decl;
let key = XmlnsDeclaration::xmlns_qname(prefix);
self.push_attribute_xmlity(key, Cow::Owned(namespace.as_str().as_bytes().to_vec()));
}
}
impl<W: Write> Serializer<W> {
fn try_start(&mut self) -> Result<(), Error> {
if !self.buffered_bytes_start_empty {
self.writer
.write_event(Event::Start(self.buffered_bytes_start.borrow()))
.map_err(Error::Io)?;
self.buffered_bytes_start_empty = true;
}
Ok(())
}
}
impl<'s, W: Write> xmlity::Serializer for &'s mut Serializer<W> {
type Ok = ();
type Error = Error;
type SerializeElement = SerializeElement<'s, W>;
type SerializeSeq = SerializeSeq<'s, W>;
fn serialize_cdata<S: AsRef<str>>(self, text: S) -> Result<Self::Ok, Self::Error> {
self.try_start()?;
self.writer
.write_event(Event::CData(BytesCData::new(text.as_ref())))
.map_err(Error::Io)
}
fn serialize_text<S: AsRef<str>>(self, text: S) -> Result<Self::Ok, Self::Error> {
self.try_start()?;
self.writer
.write_event(Event::Text(BytesText::from_escaped(text.as_ref())))
.map_err(Error::Io)
}
fn serialize_element<'a>(
self,
name: &'a ExpandedName<'a>,
) -> Result<Self::SerializeElement, Self::Error> {
self.try_start()?;
Ok(SerializeElement {
serializer: self,
name: name.into_owned(),
include_prefix: IncludePrefix::default(),
preferred_prefix: None,
})
}
fn serialize_seq(self) -> Result<Self::SerializeSeq, Self::Error> {
Ok(SerializeSeq { serializer: self })
}
fn serialize_decl<S: AsRef<str>>(
self,
version: S,
encoding: Option<S>,
standalone: Option<S>,
) -> Result<Self::Ok, Self::Error> {
self.try_start()?;
self.writer
.write_event(Event::Decl(BytesDecl::new(
version.as_ref(),
encoding.as_ref().map(|s| s.as_ref()),
standalone.as_ref().map(|s| s.as_ref()),
)))
.map_err(Error::Io)
}
fn serialize_pi<S: AsRef<[u8]>>(self, target: S, content: S) -> Result<Self::Ok, Self::Error> {
self.try_start()?;
self.writer
.write_event(Event::PI(BytesPI::new(format!(
"{} {}",
str::from_utf8(target.as_ref()).unwrap(),
str::from_utf8(content.as_ref()).unwrap()
))))
.map_err(Error::Io)
}
fn serialize_comment<S: AsRef<[u8]>>(self, text: S) -> Result<Self::Ok, Self::Error> {
self.try_start()?;
self.writer
.write_event(Event::Comment(BytesText::from_escaped(
str::from_utf8(text.as_ref()).unwrap(),
)))
.map_err(Error::Io)
}
fn serialize_doctype<S: AsRef<[u8]>>(self, text: S) -> Result<Self::Ok, Self::Error> {
self.try_start()?;
self.writer
.write_event(Event::DocType(BytesText::from_escaped(
str::from_utf8(text.as_ref()).unwrap(),
)))
.map_err(Error::Io)
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}