commit 23bdb9d2a077552937c1d2697fa82909bd5e95e4
parent ef53e579a2f6afa909038f0204d727785f1aeab3
Author: Antoine A <>
Date: Fri, 24 Apr 2026 10:37:56 +0200
simplify xml macro
Diffstat:
| M | src/xml.rs | | | 86 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
1 file changed, 44 insertions(+), 42 deletions(-)
diff --git a/src/xml.rs b/src/xml.rs
@@ -31,9 +31,10 @@ macro_rules! xml {
};
// Nested block
($w:ident, $name:tt $(($k:tt: $v:tt))* { $($body:tt)* }$(, $($rest:tt)*)?) => {
- $w.nest($name, &[$(($k, $v)),*], |$w| {
- xml!($w, $($body)*);
- });
+ let name = $name;
+ $w.open(name, &[$(($k, $v)),*]);
+ xml!($w, $($body)*);
+ $w.close(name);
$(xml!($w, $($rest)*);)*
};
// Empty element
@@ -51,11 +52,15 @@ macro_rules! xml {
#[macro_export]
macro_rules! xml_build {
($name:tt $(($k:tt: $v:tt))* { $($body:tt)* }) => {
- $crate::xml::XmlWriter::build(|w| {
- w.nest($name, &[$(($k, $v)),*], |w| {
- xml!(w, $($body)*);
- });
- })
+ {
+ let mut writer = crate::xml::XmlWriter::init();
+ let w = &mut writer;
+ let name = $name;
+ w.open(name, &[$(($k, $v)),*]);
+ xml!(w, $($body)*);
+ w.close(name);
+ writer.finish()
+ }
};
}
@@ -63,27 +68,18 @@ pub struct XmlWriter {
buff: String,
}
impl XmlWriter {
- pub fn build<F>(f: F) -> String
- where
- F: FnOnce(&mut Self),
- {
+ pub fn init() -> Self {
let buff = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>"#.to_owned();
-
- let mut tmp = Self { buff };
- f(&mut tmp);
- tmp.buff
+ Self { buff }
}
- pub fn nest<F>(&mut self, name: &str, attrs: &[(&str, &str)], f: F)
- where
- F: FnOnce(&mut Self),
- {
+ pub fn open(&mut self, name: &str, attrs: &[(&str, &str)]) {
self.buff.push('<');
self.write_tag_attrs(name, attrs);
self.buff.push('>');
+ }
- f(self);
-
+ pub fn close(&mut self, name: &str) {
self.buff.push_str("</");
self.buff.push_str(name);
self.buff.push('>');
@@ -96,7 +92,9 @@ impl XmlWriter {
}
pub fn text<D: Display>(&mut self, name: &str, attrs: &[(&str, &str)], content: D) {
- self.nest(name, attrs, |w| w.write_escaped(content));
+ self.open(name, attrs);
+ self.write_escaped(content);
+ self.close(name);
}
fn write_tag_attrs(&mut self, name: &str, attrs: &[(&str, &str)]) {
@@ -112,28 +110,32 @@ impl XmlWriter {
}
fn write_escaped<D: Display>(&mut self, content: D) {
- struct EscapingWriter<'a>(&'a mut String);
-
- impl<'a> std::fmt::Write for EscapingWriter<'a> {
- fn write_str(&mut self, s: &str) -> std::fmt::Result {
- for c in s.chars() {
- match c {
- '<' => self.0.push_str("<"),
- '>' => self.0.push_str(">"),
- '&' => self.0.push_str("&"),
- '\'' => self.0.push_str("'"),
- '"' => self.0.push_str("""),
- _ => self.0.push(c),
- }
+ std::fmt::write(self, format_args!("{content}")).unwrap();
+ }
+
+ pub fn finish(self) -> String {
+ self.buff
+ }
+}
+
+/// Write XML text content following XML escape rules
+impl<'a> std::fmt::Write for XmlWriter {
+ fn write_str(&mut self, s: &str) -> std::fmt::Result {
+ if s.contains(&['<', '>', '&', '\'', '"']) {
+ for c in s.chars() {
+ match c {
+ '<' => self.buff.push_str("<"),
+ '>' => self.buff.push_str(">"),
+ '&' => self.buff.push_str("&"),
+ '\'' => self.buff.push_str("'"),
+ '"' => self.buff.push_str("""),
+ _ => self.buff.push(c),
}
- Ok(())
}
+ } else {
+ self.buff.push_str(s);
}
- std::fmt::write(
- &mut EscapingWriter(&mut self.buff),
- format_args!("{content}"),
- )
- .unwrap();
+ Ok(())
}
}