Crates.io | format_xml |
lib.rs | format_xml |
version | 0.3.0 |
source | src |
created_at | 2019-08-16 16:52:08.748754 |
updated_at | 2022-07-28 15:09:59.011768 |
description | Fast, minimal, feature-rich, xml-like formatting syntax for Rust! |
homepage | |
repository | https://github.com/CasualX/format_xml |
max_upload_size | |
id | 157412 |
size | 42,452 |
Fast, minimal, feature-rich, xml-like formatting syntax for Rust!
We say xml-like because due to limitations and flexibility some concessions had to be made; see the examples below.
Features include:
In your Cargo.toml, add:
[dependencies]
format_xml = "0.2"
let point = (20, 30);
let name = "World";
let string = format_xml::format! {
<svg width="200" height="200">
<line x1="0" y1="0" x2={point.0} y2={point.1} stroke="black" stroke-width="2" />
<text x={point.1} y={point.0}>"Hello '"{name}"'!"</text>
</svg>
};
assert_eq!(string, r#"<svg width="200" height="200"><line x1="0" y1="0" x2="20" y2="30" stroke="black" stroke-width="2" /><text x="30" y="20">Hello 'World'!</text></svg>"#);
The value arguments can be arbitrary expressions. They are inlined in the formatting braces and are outside the string literals.
The values inside formatting braces are escaped by default, the text literals are not. Use the escape hatch to bypass the automatic escaping.
let value = 42;
let string = format_xml::format! {
<span data-value={value}>{value:#x?}</span>
};
assert_eq!(string, r#"<span data-value="42">0x2a</span>"#);
The rules for the specifiers are exactly the same as the standard library of Rust.
let value = "\"quote\"";
let text = "<script>&</script>";
let string = format_xml::format! {
<p data-value={value}>{text}</p>
};
assert_eq!(string, r#"<p data-value=""quote""><script>&</script></p>"#);
The values inside formatting braces are escaped by default, the text literals are not.
<
, &
, >
.<
, &
, >
, '
, "
.--
by removing it altogether.]]>
.Escaping is not implemented in some HTML contexts:
inside <script>
, <style>
tags or their respective attribute equivalents (event lers and inline styles),
do not format user controlled values in these locations!
let string = format_xml::format! {
<!doctype html>
<?xml version="1.0" encoding="UTF-8"?>
<tag-name></tag-name>
<self-closing-tag />
<!-- "comment" -->
<![CDATA["cdata"]]>
};
assert_eq!(string, r#"<!doctype html><?xml version="1.0" encoding="UTF-8"?><tag-name></tag-name><self-closing-tag /><!-- comment --><![CDATA[cdata]]>"#);
Examples of element naming and namespace syntax support:
let string = format_xml::format! {
<tag>
<tag-foo>
<tag.foo>
<ns:tag>
<"_t-0.z">
};
assert_eq!(string, r#"<tag><tag-foo><tag.foo><ns:tag><_t-0.z>"#);
There are no restrictions on matching open/close tags or reject tags which cannot be self-closing.
Unfinished implementation:
<!doctype>
tag is barely functional.<?xml?>
tag is barely functional.let switch = true;
let opt = Some("World");
let string = format_xml::format! {
if let Some(name) = (opt) {
<h1>"Hello "{name}</h1>
}
else if (switch) {
<h1>"Hello User"</h1>
}
};
assert_eq!(string, "<h1>Hello World</h1>");
let string: Result<f32, i32> = Err(13);
let string = format_xml::format! {
match string {
Ok(f) => <i>{f}</i>,
Err(i) => <b>{i}</b>,
}
};
assert_eq!(string, "<b>13</b>");
let string = format_xml::format! {
<ul>
for i in (1..=5) {
let times_five = i * 5;
<li>{i}"*5="{times_five}</li>
}
</ul>
};
assert_eq!(string, "<ul><li>1*5=5</li><li>2*5=10</li><li>3*5=15</li><li>4*5=20</li><li>5*5=25</li></ul>");
Control flow is only supported outside tags, not in attributes.
fn compose(f: &mut std::fmt::Formatter, a: i32) -> std::fmt::Result {
format_xml::write!(f, <span>{a}</span>)
}
let string = format_xml::format! {
<p>|f| compose(f, 42)?;</p>
};
assert_eq!(string, r#"<p><span>42</span></p>"#);
Closure syntax provides an escape hatch to inject code if needed.
The argument's type is &mut Formatter
.
Important! Anything written to the formatter f
is not escaped.
This makes it useful to compose different components wich is not possible with {}
.
Licensed under MIT License, see license.txt.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, shall be licensed as above, without any additional terms or conditions.