4 个版本 (重大更新)
0.4.0 | 2024年6月5日 |
---|---|
0.3.0 | 2024年6月3日 |
0.2.0 | 2024年6月2日 |
0.1.0 | 2024年6月2日 |
#2108 in 过程宏
每月下载量 184 次
用于 nxml-rs
18KB
257 行代码(不包括注释)
nxml-rs
NXML 是一个伪 XML 解析器,可以读取和写入来自 Noita 的格式奇特且经常无效的 XML 文件。NXML(之前链接的 C#/.NET 版本)本身是来自 Poro 的 XML 解析器的移植,Poro 是 Noita 运行的自定义 Falling Everything 引擎所使用的。
简而言之,nxml-rs 是一个与 Noita 解析器完全等价的 XML 解析器。它对 XML 规范的遵循程度与 Noita 本身一样低。它还可以以字符串形式生成语义等效的输出。
此外(仅为了乐趣),nxml-rs 提供了一个 nxml!
宏,允许你通过直接在 Rust 代码中编写几乎类似于 XML 的内容(文本内容需要一些额外的字符,并且通常不支持,Noita 本身也并不真正使用它)来创建 nxml 元素。
因为它是 Rust,所以相对容易实现,解析几乎是零拷贝的 - 唯一的例外是非连续的裸文本,<a>hello<b/>world</a>
,这种情况非常罕见,并且是 noita 解析器处理该问题的保留怪癖,通过 Cow
处理。
示例
use nxml_rs::*;
let mut entity = nxml_rs::parse(r#"
<Entity>
<LuaComponent
script_source_file="mods/blah/etc/test.lua"
execute_every_n_frame="-1">
</LuaComponent>
<TestComponent blah="blah" />
</Entity>
"#).unwrap();
// A little DSL sugar thing, / is alias for .child("name").unwrap(),
// and % is for .attr("name").unwrap()
assert_eq!("-1", &entity / "LuaComponent" % "execute_every_n_frame");
let a_lot = 0;
let speed = 0;
// Make a new element with builder methods
let extra = Element::new("ElectricityComponent")
.with_attr("energy", a_lot)
.with_attr("probability_to_heat", "0")
.with_attr("speed", speed);
// But it's more convenient to use the macro, the builder is rarely ever
// needed (and the following macro expands to above code)
let extra = nxml! {
<ElectricityComponent energy={a_lot} probability_to_heat="0" {speed} />
};
// Clone everything into owned strings, making it a bit nicer to work with
let mut owned = entity.to_owned();
// A modification - entity.children is just a vec ¯\_(ツ)_/¯
owned.children.insert(1, extra);
// Still has the sugar
assert_eq!("0", &owned / "ElectricityComponent" % "probability_to_heat");
// And can be rendered back into a string (.display() making it pretty-printed)
assert_eq!(owned.display().to_string(), r#"
<Entity>
<LuaComponent script_source_file="mods/blah/etc/test.lua" execute_every_n_frame="-1"/>
<ElectricityComponent energy="0" probability_to_heat="0" speed="0"/>
<TestComponent blah="blah"/>
</Entity>
"#.trim());
// DSL is defined for both of them, and / works with &mut
(&mut owned / "LuaComponent").remove_attr("execute_every_n_frame");
(&mut entity / "LuaComponent").remove_attr("execute_every_n_frame");
entity.children.remove(1);
// The EntityRef can be rendered too
assert_eq!(entity.to_string(), "<Entity><LuaComponent script_source_file=\"mods/blah/etc/test.lua\"/></Entity>");
Cargo 功能
indexmap
- 使用来自indexmap
crate 的IndexMap
替代HashMap
作为属性。如果你想在输出中保留属性的顺序,这很有用。默认启用,你可以禁用它来去除那个依赖项,如果你不关心属性顺序。
依赖项
~245–680KB
~16K SLoC