10 个版本 (5 个破坏性更新)
使用旧的 Rust 2015
0.6.0 | 2024年2月19日 |
---|---|
0.5.0 | 2022年1月27日 |
0.4.3 | 2021年6月24日 |
0.4.1 | 2020年10月19日 |
0.1.0 | 2018年6月1日 |
#305 in 解析器实现
2,306 下载/月
在 8 个crate中使用(直接使用6个)
46KB
674 行
quickxml_to_serde
使用 quick-xml 和 serde 将 XML 转换为 JSON。受 node2object 启发。
使用示例
基本
依赖
use std::fs::File;
use std::io::prelude::*;
use quickxml_to_serde::xml_string_to_json;
Rust 代码执行转换
// read an XML file into a string
let mut xml_file = File::open("test.xml")?;
let mut xml_contents = String::new();
xml_file.read_to_string(&mut xml_contents)?;
// convert the XML string into JSON with default config params
let json = xml_string_to_json(xml_contents, &Config::new_with_defaults());
println!("{}", json);
自定义配置
以下配置示例将默认行为更改为
- 将数字开头的数字视为字符串。例如,
0001
将被转换为"0001"
- 不要为从属性创建的 JSON 属性添加前缀
- 将
text
作为 XML 文本节点值的 JSON 属性名称,其中文本与其他节点混合 - 排除输出中的空元素
let conf = Config::new_with_custom_values(true, "", "text", NullValue::Ignore);
强制执行 JSON 类型
基于绝对路径或正则表达式进行匹配
您可以覆盖 XML 中的绝对路径的类型
let config = Config::new_with_defaults()
.add_json_type_override("/a/b", JsonArray::Always(JsonType::AlwaysString));
或者您可以根据正则表达式进行匹配!
let config = Config::new_with_defaults()
.add_json_type_override(
Regex::new(r"element").unwrap(),
JsonArray::Always(JsonType::Infer)
);
字符串
此库的默认操作是尝试推断标量数据类型,这些类型可以是 JSON 中的 int
、float
、bool
或 string
。有时这并不理想,如以下示例所示。假设属性 id
总是数字,可以安全地转换为 JSON 整数。第一个两个用户的 card_number
元素看起来像数字,而第三个用户的 card_number
元素是字符串。这种 JSON 类型的不一致性使得反序列化结构变得困难,所以我们可能更愿意告诉转换器为某些 XML 节点使用特定的 JSON 数据类型。
<users>
<user id="1">
<name>Andrew</name>
<card_number>000156</card_number>
</user>
<user id="2">
<name>John</name>
<card_number>100263</card_number>
</user>
<user id="3">
<name>Mary</name>
<card_number>100263a</card_number>
</user>
</users>
在您的Cargo.toml文件中使用quickxml_to_serde = { version = "0.4", features = ["json_types"] }
特性来启用对某些XML节点使用类似xPath的表示法强制JSON类型的支持。
示例XML文档
<a attr1="007"><b attr1="7">true</b></a>
配置使得属性attr1="007"
始终以JSON字符串形式出现
let conf = Config::new_with_defaults().add_json_type_override("/a/@attr1", JsonArray::Infer(JsonType::AlwaysString));
配置使得<b />
的属性和文本节点始终以JSON字符串形式出现
let conf = Config::new_with_defaults()
.add_json_type_override("/a/@attr1", JsonArray::Infer(JsonType::AlwaysString))
.add_json_type_override("/a/b/@attr1", JsonArray::Infer(JsonType::AlwaysString))
.add_json_type_override("/a/b", JsonArray::Infer(JsonType::AlwaysString));
布尔值
JSON中有效的布尔值只有两个:true
和false
。另一方面,像True
、False
、1
和0
这样的值在编程语言和数据格式中很常见。使用带有“true”值列表的JsonType::Bool(...)
类型将任意布尔值转换为JSON布尔值。
let conf = Config::new_with_defaults()
.add_json_type_override("/a/b", JsonArray::Infer(JsonType::Bool(vec!["True","true","1","yes"])));
数组
具有相同名称的多个节点会自动转换为JSON数组。例如,
<a>
<b>1</b>
<b>2</b>
</a>
被转换为
{ "a":
{ "b": [1,2] }
}
默认情况下,单个元素如
<a>
<b>1</b>
</a>
被转换为标量值或映射
{ "a":
{ "b": 1 }
}
您可以使用add_json_type_override()
与JsonArray::Always()
一起使用,以创建无论元素数量如何的JSON数组,使<a><b>1</b></a>
变为{ "a": { "b": [1] } }
。
JsonArray::Always()
和JsonArray::Infer()
可以指定应使用的底层JSON类型,例如。
JsonArray::Infer(JsonType::AlwaysString)
- 推断数组,将值转换为JSON字符串JsonArray::Always(JsonType::Infer)
- 总是包裹值在JSON数组中,推断值类型JsonArray::Always(JsonType::AlwaysString)
- 总是将值包装在JSON数组中并将值转换为JSON字符串
let config = Config::new_with_defaults()
.add_json_type_override("/a/b", JsonArray::Always(JsonType::AlwaysString));
空XML节点(如 <a><b /></a>
)的转换取决于 NullValue
设置。例如,
let config = Config::new_with_custom_values(false, "@", "#text", NullValue::Ignore)
.add_json_type_override("/a/b", JsonArray::Always(JsonType::Infer));
将 <a><b /></a>
转换为
{"a": null}
相同的 config
与 NullValue::Null
转换为
{"a": { "b": [null] }}
无法得到空数组,例如 {"a": { "b": [] }}
。
有关 Config
结构及其成员的详细信息,请参阅嵌入式文档。
转换细节
- XML元素的顺序不保留
- 命名空间标识符被删除。例如,
<xs:a>123</xs:a>
变为{ "a":123 }
- 整数和浮点数被转换为JSON整数和浮点数,除非在
Config
中指定了JSON类型。 - XML属性成为与子元素同一级别的JSON属性。例如。
<Test TestId="0001">
<Input>1</Input>
</Test>
被转换为
"Test":
{
"Input": 1,
"TestId": "0001"
}
- XML声明被删除。例如,
<?xml version="1.0"?>
。 - XML命名空间定义被删除。例如,
<Tests xmlns="http://www.adatum.com" />
变为"Tests":{}
- 忽略处理指令、注释和DTD
- XML中的CDATA导致JSON格式错误
- XML属性可以通过
Config::xml_attr_prefix
进行前缀命名。例如,使用默认前缀@
将<a b="y" />
转换为{ "a": {"@b":"y"} }
。您可以选择不使用前缀或设置自己的值。 - 具有文本节点的复杂XML元素将XML文本节点值放入名为
Config::xml_text_node_prop_name
的JSON属性中。例如,将xml_text_node_prop_name
设置为text
将转换
<CardNumber Month="3" Year="19">1234567</CardNumber>
为
{
"CardNumber": {
"Month": 3,
"Year": 19,
"text": 1234567
}
}
- 具有相同名称的元素会被收集到数组中。例如。
<Root>
<TaxRate>7.25</TaxRate>
<Data>
<Category>A</Category>
<Quantity>3</Quantity>
<Price>24.50</Price>
</Data>
<Data>
<Category>B</Category>
<Quantity>1</Quantity>
<Price>89.99</Price>
</Data>
</Root>
被转换为
{
"Root": {
"Data": [
{
"Category": "A",
"Price": 24.5,
"Quantity": 3
},
{
"Category": "B",
"Price": 89.99,
"Quantity": 1
}
],
"TaxRate": 7.25
}
}
- 如果将上述示例中的
TaxRate
元素插入到Data
元素之间,它仍然会生成相同的JSON,其中所有Data
属性被组合成一个单独的数组。
更多信息与示例
有关更多用法示例,请参阅tests.rs。
边缘情况
XML和JSON不是直接兼容的,需要进行1:1转换,除非转换器有额外的提示。如果您遇到任何不正确的转换,请提交一个问题。
依赖
~4–6MB
~107K SLoC