#xml-parser #xml #xml-data #xavier #ease #process #versatile

xavier-internal

Xavier的内部模块。Xavier是一个轻量级且多功能的XML解析库,旨在简化以轻松和高效的方式处理XML数据的过程。

2个版本

0.1.2 2024年4月19日
0.1.1 2024年4月19日

18#versatile

Download history 1/week @ 2024-05-29 1/week @ 2024-06-19 3/week @ 2024-06-26 1/week @ 2024-07-03 38/week @ 2024-07-10 45/week @ 2024-07-17 73/week @ 2024-07-24 161/week @ 2024-07-31 320/week @ 2024-08-07 989/week @ 2024-08-14

1,578 每月下载量
用于 xavier

自定义许可

29KB
461

什么是Xavier?

介绍Xavier:一个受Serde启发的简化XML解析库 灵感。为什么叫Xavier?嗯...它始于X,是我脑海中第一个想到的名字,没有其他。

Xavier是一个轻量级且多功能的XML解析库,旨在简化以轻松和高效的方式处理XML数据的过程。

尽管速度是Xavier设计时考虑的因素之一,但重要的是要强调,原始速度并不是其主要目标。相反,Xavier优先考虑易用性和人体工程学设计,旨在在不牺牲可靠性和开发者体验的情况下,简化Rust应用程序中的XML解析任务。

它必须在相对较小的xml中使用,因为它将所有数据存储在内存中。

注意1:目前不支持UTF-16。需要努力!欢迎提交PR。

注意2:我们的DOM实现(WIP)旨在尽可能接近原始规范,但由于规范和Rust在处理概念上的差异,实现完美匹配是困难的。

为什么不扩展Serde?

有人已经做到了,但我更喜欢从头开始。此外,由于Xavier专注于XML解析,我认为它应该更简单,更针对该目的。

示例

序列化

从简单开始

这是可能的简单示例

#[derive(XmlSerializable)]
struct XMLObject {
    pub some_string: String,
    pub some_int: i32,
    pub some_float: f32
}

// ... 
    println!(from_obj(&instance));
// ... 

应该产生

<XMLObject>
    <some_string>Some Content A</some_string>
    <some_int>0</some_int>
    <some_float>0.0</some_float>
</XMLObject>

名称

改进名称

#[derive(XmlSerializable)]
#[xml(name="object", case="Camel", prefix="xml_", suffix="Item", no_suffix, no_prefix)]
struct XMLObject {
    #[xml(name="just_string")]
    pub some_string: String,
    pub some_int: i32,
    pub some_float: f32
}

// ... 
    println!(from_obj(&instance));
// ... 

应该产生

<object>
    <xmlJustStringItem>Some Content A</xmlJustStringItem>
    <xmlSomeIntItem>0</xmlSomeIntItem>
    <xmlSomeFloatItem>0.0</xmlSomeFloatItem>
</object>

注意1:使用camel config将产生所有元素使用相同的约定。

注意2:可以使用convert_case crate支持的除Randoms之外的所有情况。

注意3:ignore_case可以用来忽略元素中的大小写。

命名空间

与命名空间一起工作

#[derive(XmlSerializable)]
#[xml(ns="xml", name="object", case="Camel")]
struct XMLObject {
    #[xml(xmlns)]
    pub namespaces: Namespaces,
    #[xml(name="just_string")]
    pub some_string: String,
    pub some_int: i32,
    pub some_float: f32
}

// ... 
    let xmlns = namespaces!(xml = "http://www.w3.org/XML/1998/namespace", xhtml = "http://www.w3.org/1999/xhtml");
    XMLObject{ namespaces: xmlns, ... }
    //...
    println!(from_obj(&instance));
    // ... 

应该产生

<xml:object 
   xmlns:xml="http://www.w3.org/XML/1998/namespace" 
   xmlns:xhtml="http://www.w3.org/1999/xhtml">
        <xml:justString>Some Content A</justString>
        <xml:someInt>0</someInt>
        <xml:someFloat>0.0</someFloat>
</xml:object>

注意: #[xml(xmlns)] 必须只在根元素上使用,并且只能使用一次。

属性

与属性一起工作

#[derive(XmlSerializable)]
#[xml(ns="a", name="object", case="Camel")]
struct XMLObject {
    #[xml(attribute, name="just_string")]
    pub some_string: String,
    pub some_int: i32,
    pub some_float: f32
}

// ... 
    println!(from_obj(&instance));
// ... 

应该产生

<a:xmlObject justString="Some Text">
    <a:someInt>0</a:someInt> 
    <a:someFloat>0</a:someFloat> 
</a:xmlObject>

注意:use_suffix="false" 或 use_prefix="true" 可以用来强制使用后缀或前缀。

枚举

与枚举一起工作

#[derive(XmlSerializable)]
enum CustomEnum {
    ValueA
}

// Many libs don't implement of infer any string value in this case, we are no exception.
impl Display for CustomEnum {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let str = match self {
            CustomEnum::ValueA => { "Value A".to_string() },
        };
        write!(f, "{}", str)
    }
}

#[derive(XmlSerializable)]
#[xml(name="object")]
struct XMLObject {
    pub enum_field: CustomEnum,
}

// ...
     println!(from_obj(&instance));
// ...

应该产生

<object>
    <enum_field>ValueA</enum_field>
</object>

未命名的结构体

使用类似这样的单元结构体

#[derive(XmlSerializable)]
#[xml(ns="a", name="object")]
pub struct XMLObject(String);

应该产生

<a:object>Some Text</a:object>

注意:在这种情况下不支持多个属性,否则将产生编译错误。

单元结构体

使用类似这样的单元结构体

#[derive(XmlSerializable)]
#[xml(name="object")]
struct XMLObject;

应该产生

<object></object>

作为根元素不太有用...但考虑在更树形的环境中将其用作标志字段。

像这样组合结构体

#[derive(XmlSerializable)]
#[xml(name="my_child")]
struct Child {
    pub child_field_a: String,
}

#[derive(XmlSerializable)]
#[xml(name="object", case="Camel")]
struct XMLObject {
    pub field_a: String,
    #[xml(tree)] //Same as #[xml(flatten)] 
    pub child: Child
}

应该产生

<object>
    <fieldA>Some value</fieldA>
    <my_child>
        <child_field_a>Other value</child_field_a>
    </my_child>    
</object>

注意:案例的范围是元素的。同样适用于命名空间。

集合

像这样组合结构体

#[derive(XmlSerializable)]
#[xml(name="my_child")]
struct Child {
    pub child_field_a: String,
}

#[derive(XmlSerializable)]
#[xml(name="object", case="Camel")]
struct XMLObject {
    pub field_a: String,
    pub children: Vec<Child>
}

应该产生

<object>
	<fieldA>Some Text</fieldA>
	<children>
		<my_child>
			<child_field_a>Child A</child_field_a>
		</my_child>
		<my_child>
			<child_field_a>Child B</child_field_a>
		</my_child>
	</children>
</object>

注意:也支持 HashMap<String, T: XmlSerializable>,但没有命名效果。

将结构体作为标签

配置嵌套结构体如下

#[derive(XmlSerializable)]
#[xml(tag, name="child")]
struct Child {
    #[xml(attribute, name="attr")]
    pub attribute: String,
    #[xml(value)]  
    pub value: String,
}

#[derive(XmlSerializable)]
#[xml(name="object", case="Camel")]
struct XMLObject {
    pub field_a: String,
    #[xml(tree)]
    pub child: Child
}

应该产生

<object>
    <fieldA>Some value</fieldA>
    <child attr="Attr Value">Other value</child>    
</object>

注意 1:你可以有任意多的属性,但只有一个值!注意 2:如果没有指定,字段的默认行为是属性,值为空。

XML声明

你可以这样配置XML

#[derive(XmlSerializable)]
#[declaration(version="1.0" encoding="UTF-8" standaline = "no")]
#[xml(name="xml")]
struct XMLObject {
    //...
}
// or
#[derive(XmlSerializable)]
#[declaration]
#[xml(name="xml")]
struct XMLObject {
    //...
}

应该产生

<?xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
<xml>
    ...
</xml>

注意:如果没有指定,默认声明使用 version="1.0" encoding="UTF-8" standaline = "no"

DTD

使用这个

#[derive(XmlSerializable)]
#[declaration]
#[dtd = "Note.dtd"]
#[xml(name="xml")]
struct XMLObject {
    //...
}

应该产生

<?xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
<!DOCTYPE xml SYSTEM "Note.dtd">
<xml>
    ...
</xml>

注意 1:目前不支持内联DTD。然而,我愿意探索其他方法。欢迎和感谢提交拉取请求。注意 2:XML验证不在此项目的范围内。

PI(处理指令)

使用这个

#[derive(XmlSerializable)]
#[declaration]
#[pi(something key="value" flag)]
#[xml(name="xml")]
struct XMLObject {
    //...
}

应该产生

<?xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
<?something key="value" flag?>
<xml>
    ...
</xml>

方便

CDATA

这个

  println!(cdata!("Some text & others"));  

打印这个

  <![CDATA[Some text & others]]>

文本编码

  println!(encode!("Some text & others"));  

打印这个

   Some text &amp; others

注释

这个

  println!(comment!("Some text & others"));  

打印这个

  <!--Some text & others-->

反序列化

从简单开始

这是可能的简单示例

#[derive(XmlDeserializable)]
struct XMLObject {
    pub some_string: String,
    pub some_int: i32,
    pub some_float: f32
}

// ... 
    let xml = r#"
    <XMLObject>
        <some_string>Some Content A</some_string>
        <some_int>0</some_int>
        <some_float>0.0</some_float>
    </XMLObject>"#
    
    let instance: XMLObject = from_xml(&xml)?;
    assert_eq!(instance.some_string, "Some Content A");
    assert_eq!(instance.some_int, 0);
    assert_eq!(instance.some_float, 0.0);
// ... 

如您所见,这与序列化中的标签结构相同。查看大量示例 这里!

名称、属性、枚举、未命名结构体、单元结构体、树、集合和结构体作为标签

与序列化完全一样,但方向相反。相同的标签! 😊

方便

XML声明

可以使用这个宏解析声明!

    let (version, encoding, standalone) = declaration!(&xml);

DTD

可以使用这个宏解析DTD!

    let (target, file) = dtd!(&xml);

PI(处理指令)

可以使用这个宏解析PI!

    instructions!(&xml, | tag, instruction, params | {
        // DO something related with the instruction itself
    });

文本解码

  println!(decode!("Some text &amp; others"));  

打印这个

   Some text & others

命名空间

将作为正常标签属性可用。

错误

Xavier DOM(WIP)实现由于规范使用 DOMException,但 "Xavier DeSer tiene un PError" ʕ•ᴥ•ʔ

待办事项

具有生存期、引用和其他结构的结构体

困难:简单

来自 deserialize::parser::complex::tokens::types 的 TypeParser 中的函数以静态结构化的方式处理类型解析,期望元素遵循预定义的顺序。虽然对于简单的Rust元素有效,但在处理更复杂的Rust结构时可能需要额外的时间和精力。尽管如此,这项任务是可管理的,并且通过仔细的关注,我们可以有效地导航这些复杂性。

如果需要,你可以修改 constructors.rs 中的对象创建过程或调整 setters/ 中的结构字段分配。

也很重要的是要指出,由于需要自我赋值,从第一天开始就支持Box 示例。在这里,您可以看到结构体的解析,如下

#[derive(XmlDeserializable, Debug)]
#[xml(name="my_child")]
struct Child {
    #[xml(attribute, name="attr")]
    pub attribute: String,
    pub child_field_a: String,
    #[xml(tree)]
    pub inner: Option<Box<Child>>
}

#[derive(XmlDeserializable, Debug)]
#[xml(name="object", case="Camel")]
struct XMLObject {
    pub field_a: String,
    #[xml(tree)]
    pub child: Child
} 

实现DOM

困难:中等

(branch feature/dom)

规范来自 https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html

DOM实现必须通过名为 "dom" 的Cargo功能访问,并可以使用如下方式使用

    //...
    let doc = to_dom(&xml);
    //...
    let xml = from_dom(&xml);
    //...        

依赖关系

~1.5MB
~25K SLoC