xsd_parser/quick_xml/
mod.rs1pub mod reader;
5
6mod attributes;
7mod deserialize;
8mod error;
9mod serialize;
10
11use std::sync::LazyLock;
12
13pub use std::io::Write as XmlWrite;
14
15pub use quick_xml::{
16 events::{BytesCData, BytesDecl, BytesEnd, BytesPI, BytesStart, BytesText, Event},
17 name::{LocalName, Namespace, QName, ResolveResult},
18 Writer,
19};
20use regex::Regex;
21
22pub use crate::models::RawByteStr;
23
24pub use self::attributes::{filter_xmlns_attributes, write_attrib, write_attrib_opt};
25pub use self::deserialize::{
26 ContentDeserializer, DeserializeBytes, DeserializeBytesFromStr, DeserializeReader,
27 DeserializeStrError, DeserializeSync, Deserializer, DeserializerArtifact, DeserializerEvent,
28 DeserializerOutput, DeserializerResult, ElementHandlerOutput, WithDeserializer,
29};
30pub use self::error::{Error, Kind as ErrorKind, UnionError, ValidateError};
31pub use self::reader::{ErrorReader, IoReader, SliceReader, XmlReader, XmlReaderSync};
32pub use self::serialize::{
33 BoxedSerializer, ContentSerializer, IterSerializer, SerializeBytes, SerializeBytesToString,
34 SerializeSync, Serializer, WithBoxedSerializer, WithSerializer,
35};
36
37#[cfg(feature = "async")]
38pub use tokio::io::AsyncWrite as XmlWriteAsync;
39
40#[cfg(feature = "async")]
41pub use self::serialize::SerializeAsync;
42
43#[cfg(feature = "async")]
44pub use self::deserialize::DeserializeAsync;
45
46#[cfg(feature = "async")]
47pub use self::reader::XmlReaderAsync;
48
49#[must_use]
51pub fn whitespace_replace(s: &str) -> String {
52 s.replace(['\t', '\n', '\r'], " ")
53}
54
55pub fn whitespace_collapse(s: &str) -> String {
57 RX_WHITESPACE_COLLAPSE.replace_all(s, " ").trim().to_owned()
58}
59
60pub fn total_digits(s: &str, expected: usize) -> Result<(), ValidateError> {
68 let m = RX_DECIMAL
69 .captures(s)
70 .ok_or(ValidateError::InvalidDecimalValue)?;
71
72 let actual = match (m.get(1), m.get(2)) {
73 (None, _) => unreachable!("Capture group 1 should be always present"),
74 (Some(a), None) => a.len(),
75 (Some(a), Some(b)) => a.len() + b.len(),
76 };
77
78 if actual <= expected {
79 Ok(())
80 } else {
81 Err(ValidateError::TotalDigits(expected))
82 }
83}
84
85pub fn fraction_digits(s: &str, expected: usize) -> Result<(), ValidateError> {
93 let m = RX_DECIMAL
94 .captures(s)
95 .ok_or(ValidateError::InvalidDecimalValue)?;
96
97 let actual = m.get(2).map(|s| s.len()).unwrap_or_default();
98
99 if actual <= expected {
100 Ok(())
101 } else {
102 Err(ValidateError::FractionDigits(expected))
103 }
104}
105
106static RX_DECIMAL: LazyLock<Regex> =
107 LazyLock::new(|| Regex::new(r"^-?([0-9]+)(?:\.([0-9]*))?$").unwrap());
108static RX_WHITESPACE_COLLAPSE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\s+").unwrap());