1 个不稳定版本
0.1.6 | 2023年7月11日 |
---|---|
0.1.5 |
|
#22 in 数据格式
2,660 每月下载量
用于 3 crates
56KB
1.5K SLoC
通过链式结构体或闭包以编程方式构建xml / html / svg。不使用模板引擎,编写看起来像rust的数据/标记。用户可以通过inline()
函数控制格式。
您可以在github和crates.io上找到tagu。文档在docs.rs
适配器示例
use tagu::build;
use tagu::prelude::*;
fn main() -> std::fmt::Result {
let a = build::elem("a");
let b = build::elem("b");
let c = build::elem("c");
let it = build::from_iter((0..5).map(|i| build::elem(format_move!("x{}", i)).inline()));
let all = a.append(b.append(c.append(it)));
tagu::render(all, tagu::stdout_fmt())
}
输出文本
<a>
<b>
<c>
<x0></x0>
<x1></x1>
<x2></x2>
<x3></x3>
<x4></x4>
</c>
</b>
</a>
堆栈示例
use tagu::build;
use tagu::prelude::*;
fn main() -> std::fmt::Result {
let all = build::from_stack(|stack| {
let a = build::elem("a");
let b = build::elem("b");
let c = build::elem("c").with_tab("→");
let mut stack = stack.push(a)?.push(b)?.push(c)?;
for i in 0..5 {
let e = build::elem(format_move!("x{}", i)).inline();
stack.put(e)?;
}
stack.pop()?.pop()?.pop()
});
tagu::render(all.with_tab(" "), tagu::stdout_fmt())
}
输出文本
<a>
<b>
→→<c>
→→→<x0></x0>
→→→<x1></x1>
→→→<x2></x2>
→→→<x3></x3>
→→→<x4></x4>
→→</c>
</b>
</a>
适配器2示例
use tagu::build;
use tagu::prelude::*;
fn main() -> std::fmt::Result {
let all = build::elem("a").append_with(|| {
elems!(
build::single("test"),
build::elem("b").append_with(|| {
let it =
build::from_iter((0..5).map(|i| build::elem(format_move!("x{}", i)).inline()));
build::elem("c").append_with(|| it)
}),
build::elem("bbbb").append_with(|| {
elems!(
tagu::util::comment("this is comment"),
build::single("k").with(("apple", 5))
)
})
)
});
tagu::render(all, tagu::stdout_fmt())
}
输出
<a>
<test/>
<b>
<c>
<x0></x0>
<x1></x1>
<x2></x2>
<x3></x3>
<x4></x4>
</c>
</b>
<bbbb>
<!--this is comment-->
<k apple="5"/>
</bbbb>
</a>
SVG示例
use tagu::build;
use tagu::prelude::*;
fn main() -> std::fmt::Result {
let width = 100.0;
let height = 100.0;
let rect = build::single("rect").with(attrs!(
("x1", 0),
("y1", 0),
("rx", 20),
("ry", 20),
("width", width),
("height", height),
("style", "fill:blue")
));
let style = build::elem("style")
.inline()
.append(build::raw(".test{fill:none;stroke:white;stroke-width:3}"));
let svg = build::elem("svg").with(attrs!(
("xmlns", "http://www.w3.org/2000/svg"),
("viewBox", format_move!("0 0 {} {}", width, height))
));
let rows = build::from_stack(|mut f| {
for r in (0..50).step_by(5) {
if r % 10 == 0 {
let c = build::single("circle").with(attrs!(("cx", 50.0), ("cy", 50.0), ("r", r)));
f.put(c)?;
} else {
let r = build::single("rect").with(attrs!(
("x", 50 - r),
("y", 50 - r),
("width", r * 2),
("height", r * 2)
));
f.put(r)?;
}
}
Ok(f)
});
let table = build::elem("g").with(("class", "test")).append(rows);
let all = svg.append(style).append(rect).append(table);
tagu::render(all, tagu::stdout_fmt())
}
输出
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<style>.test{fill:none;stroke:white;stroke-width:3}</style>
<rect x1="0" y1="0" rx="20" ry="20" width="100" height="100" style="fill:blue"/>
<g class="test">
<circle cx="50" cy="50" r="0"/>
<rect x="45" y="45" width="10" height="10"/>
<circle cx="50" cy="50" r="10"/>
<rect x="35" y="35" width="30" height="30"/>
<circle cx="50" cy="50" r="20"/>
<rect x="25" y="25" width="50" height="50"/>
<circle cx="50" cy="50" r="30"/>
<rect x="15" y="15" width="70" height="70"/>
<circle cx="50" cy="50" r="40"/>
<rect x="5" y="5" width="90" height="90"/>
</g>
</svg>
查看其他示例输出https://github.com/tiby312/tagu/tree/main/assets
使用哪种方法?
您可以通过构建长适配器链来追加元素,或者您可以在动态渲染元素时将其渲染到写入器。在链式操作中,您不需要担心处理错误,因为在链式操作过程中实际上没有任何内容被写入。然而,您通常需要“颠倒”构建东西。您必须首先构建最嵌套的元素,然后才能将其附加到更大的元素中。在动态渲染中,您确实需要处理错误,但元素的处理顺序与它们被渲染的顺序相匹配。您可以混合使用,因为您可以从闭包创建元素,然后将这些元素链接在一起。
内联函数
默认情况下,标签插入换行符和制表符。如果您在一个元素上调用inline()
,那么它内部的所有元素都将内联。
是否有转义XML保护?
属性通过转义保护器进行传递。标签名称通过转义保护器进行传递。用户可以使用 raw_escpapable()
或 from_stack_escapable()
函数来绕过这一限制。这将返回唯一不实现 elem::Locked
的元素类型。 render()
需要链式元素实现 Locked
。如果用户链入原始元素,则整个链将不会实现 Locked
。相反,用户将不得不使用 render_escapable()
。元素链式系统通过让每个元素实现一个 render_head()
和一个 render_tail()
函数来工作。
标签器包发生了什么?
我让标签器包保持原样,并创建了一个全新的包,因为虽然它具有标签器的所有功能,但它更加复杂。有些人可能更喜欢标签器的简单性。然而,我建议人们选择 tagu 而不是 tagger,因为它在我看来更加灵活。能够在我的经验中将元素链像结构体一样传递的能力非常有用。