pub mod reader;
mod deserialize;
mod error;
mod serialize;
use std::sync::LazyLock;
pub use std::io::Write as XmlWrite;
pub use quick_xml::{
events::{BytesCData, BytesDecl, BytesEnd, BytesPI, BytesStart, BytesText, Event},
name::{LocalName, Namespace, QName, ResolveResult},
Writer,
};
use regex::Regex;
pub use crate::misc::RawByteStr;
pub use self::deserialize::{
ContentDeserializer, DeserializeBytes, DeserializeBytesFromStr, DeserializeHelper,
DeserializeStrError, DeserializeSync, Deserializer, DeserializerArtifact, DeserializerEvent,
DeserializerOutput, DeserializerResult, ElementHandlerOutput, WithDeserializer,
WithDeserializerFromBytes,
};
pub use self::error::{Error, Kind as ErrorKind, UnionError, ValidateError};
pub use self::reader::{ErrorReader, IoReader, SliceReader, XmlReader, XmlReaderSync};
pub use self::serialize::{
BoxedSerializer, CollectNamespaces, ContentSerializer, DerefIter, IterSerializer,
SerializeBytes, SerializeBytesToString, SerializeHelper, SerializeSync, Serializer,
WithBoxedSerializer, WithSerializeToBytes, WithSerializer,
};
#[cfg(feature = "async")]
pub use tokio::io::AsyncWrite as XmlWriteAsync;
#[cfg(feature = "async")]
pub use self::serialize::SerializeAsync;
#[cfg(feature = "async")]
pub use self::deserialize::DeserializeAsync;
#[cfg(feature = "async")]
pub use self::reader::XmlReaderAsync;
#[must_use]
pub fn whitespace_replace(s: &str) -> String {
s.replace(['\t', '\n', '\r'], " ")
}
pub fn whitespace_collapse(s: &str) -> String {
RX_WHITESPACE_COLLAPSE.replace_all(s, " ").trim().to_owned()
}
pub fn total_digits(s: &str, expected: usize) -> Result<(), ValidateError> {
let m = RX_DECIMAL
.captures(s)
.ok_or(ValidateError::InvalidDecimalValue)?;
let actual = match (m.get(1), m.get(2)) {
(None, _) => unreachable!("Capture group 1 should be always present"),
(Some(a), None) => a.len(),
(Some(a), Some(b)) => a.len() + b.len(),
};
if actual <= expected {
Ok(())
} else {
Err(ValidateError::TotalDigits(expected))
}
}
pub fn fraction_digits(s: &str, expected: usize) -> Result<(), ValidateError> {
let m = RX_DECIMAL
.captures(s)
.ok_or(ValidateError::InvalidDecimalValue)?;
let actual = m.get(2).map(|s| s.len()).unwrap_or_default();
if actual <= expected {
Ok(())
} else {
Err(ValidateError::FractionDigits(expected))
}
}
static RX_DECIMAL: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^-?([0-9]+)(?:\.([0-9]*))?$").unwrap());
static RX_WHITESPACE_COLLAPSE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\s+").unwrap());