Rust中使用serde-xml-rs解析混合元素与无标签文本的XML
Rust 解析混合子元素与无标签文本的XML解决方案
报错原因
你遇到的duplicate field $value报错是因为serde-xml-rs的$value字段默认仅支持捕获单个文本节点,而你的示例XML中<element>根标签下存在三个节点:
<subelement>标签前的换行、缩进空白(属于文本节点)- 带id属性的
<subelement>元素节点 <subelement>标签后的arbitrary text文本加末尾空白(属于第二个文本节点)
两个文本节点同时映射到同一个$value字段,就触发了重复字段冲突。
解决方案
方案1:用数组存储所有文本节点后过滤合并
将存储文本的字段修改为Vec<String>类型,serde会自动收集所有零散的文本节点,你可以后续自行过滤空白内容、拼接得到目标文本,实现代码如下:
use serde_derive::{Deserialize, Serialize}; use serde_xml_rs::from_str; #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename = "element")] struct Element { #[serde(default)] subelement: Option<SubElement>, #[serde(rename = "$value", default)] text_parts: Vec<String>, } impl Element { /// 提取有效文本,自动过滤空白内容 pub fn get_text(&self) -> String { self.text_parts .iter() .map(|s| s.trim()) .filter(|s| !s.is_empty()) .collect::<Vec<_>>() .join(" ") } } #[derive(Serialize, Deserialize, Debug, PartialEq)] struct SubElement { id: i32, } fn main() { const XML: &str = r#" <element> <subelement id="123"></subelement> arbitrary text </element> "#; let actual: Element = from_str(XML).unwrap(); // 验证解析结果 assert_eq!(actual.subelement, Some(SubElement { id: 123 })); assert_eq!(actual.get_text(), "arbitrary text"); println!("解析结果:{:?}", actual); println!("提取到的无标签文本:{}", actual.get_text()); }
方案2:枚举适配任意混合内容
如果你的XML存在文本和子元素任意穿插的场景,可以用枚举统一表示不同类型的节点,适配性更强:
use serde_derive::{Deserialize, Serialize}; use serde_xml_rs::from_str; /// 节点类型枚举,匹配所有可能的子节点和文本 #[derive(Serialize, Deserialize, Debug, PartialEq)] enum Node { #[serde(rename = "subelement")] SubElement(SubElement), #[serde(rename = "$value")] Text(String), } #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename = "element")] struct Element { #[serde(rename = "$value", default)] nodes: Vec<Node>, } #[derive(Serialize, Deserialize, Debug, PartialEq)] struct SubElement { id: i32, } // 后续遍历nodes数组即可分别提取子元素和文本内容
可选优化:自动修剪空白
在Cargo.toml中为serde-xml-rs开启trim_text特性,库会自动修剪所有文本节点前后的空白,减少后续过滤的工作量:
serde-xml-rs = { version = "0.9.0", features = ["trim_text"] }
内容的提问来源于stack exchange,提问作者user922367
相关产品推荐
相关产品推荐

