large_xml
一个用于读取、写入大型 XML 的纯 Dart 库
用法
示例XML
所有示例代码将使用此xml字符串
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE root>
<root
xmlns:r="http://schemas.openxmlformats.org/package/2006/relationships"
xmlns:x="http://schemas.openxmlformats.org/package/2006/x"
>
<!-- comment here -->
<person age="1" r:id="2" x:id="3" ></person>
<!-- comment here -->
<x:script>
<![CDATA[function matchwo(a,b){if (a < b && a < 0) then{return 1;}else{return 0;}}]]>
</x:script>
<info>
<child x:name="child name"/>
</info>
</root>
入门
首先,你需要创建一个XmlDocument对象
该对象保存你的xml字符串并动态更新挂载的XmlNode
然后,你可以访问Xml的根xml节点
注意:如果你想缓存xml节点
你必须调用node.mount(),将节点挂载到XmlDocument
这样XmlDocument就可以在XML原始字符串更改时动态更新此XmlNode的指针。
当节点不再需要时,你应该调用node.unmount()
import 'package:large_xml/large_xml.dart';
var doc = XmlDocument.fromString(xmlstr);
var root = XmlDocument.root;
查找节点
现在我们有一个root节点引用对象
如果你想获取子节点引用,可以调用node.into()
var root = XmlDocument.root;
// find first normal start element in root chilren
// return <person/> node
var person = doc.root.into(type: XmlElementType.start);
if(person == null){
print("node not found");
}
// find first normal start element in root chilren and node name is "info"
// return <info/> node
var info = doc.root.into(selector: (n)=>n.type == XmlElementType.start && n.name == "info");
if(info == null){
print("node not found");
}
如果你想获取并行节点引用,可以调用node.next()
var root = XmlDocument.root;
var person = doc.root.into(type: XmlElementType.start)!;
// find first normal start element after person node
// return <x:script/> node
var script = person.next(type: XmlElementType.start);
if(script == null){
print("node not found");
}
// find first normal start element in root chilren and node name is "info"
// return <info/> node
var info = doc.root.next(selector: (n)=>n.type == XmlElementType.start && n.name == "info");
if(info == null){
print("node not found");
}
// find first normal start element after person node and node name is "script", ignore namespace
// return <x:script/> node
script = doc.root.next(selector: (n)=>n.type == XmlElementType.start && n.name.removeNamespace() == "script");
if(script == null){
print("node not found");
}
// find first normal start element after person node and namespace is "x"
// return <x:script/> node
script = doc.root.next(selector: (n)=>n.type == XmlElementType.start && n.name.namespace() == "x");
if(script == null){
print("node not found");
}
// find first normal start element after person node and specified whole match "x:script"
// return <x:script/> node
script = doc.root.next(selector: (n)=>n.type == XmlElementType.start && n.name == "x:script");
if(script == null){
print("node not found");
}
如果你想获取祖先节点引用,可以调用node.findAncestor()
就像into()和next()一样,它也支持type和selector
并且你可以通过node.parent轻松获取节点的父节点
节点属性
你可以使用以下方法访问节点的属性
node.containsAttributenode.getAttributenode.getAttributesnode.getAttributeNodenode.addAttribute
像这样直接获取属性值
var root = XmlDocument.root;
var person = doc.root.into(type: XmlElementType.start)!;
// directly get attribute's value
// getAttribute(key) you can pass specified or unspecified namespace attribute key,such as "id" or "x:id" or ":id"
// if you pass key like ":id", it will try to find a attribute which named 'id' and has a namespace
String? id = person.getAttribute(":id");
if(id != null){
// should be attribute r:id
print(id);
}
如果你想更新属性,请使用node.getAttributeNode,你将获得一个XmlAttribute对象
注意:XmlAttribute不应被缓存,它应该在任何写入操作后立即丢弃,所有XmlAttribute将指向错误的位置
如果你确定在持有该对象期间不会进行任何写入操作,那么你可以保留它。
提示:attr.setAttribute会自行更新,你仍然可以在setAttribute之后保留它
一些方法支持链式调用,你可以在链式调用中保留对象,否则你应该通过node.getAttributeNode重新查找它。
var root = XmlDocument.root;
var person = doc.root.into(type: XmlElementType.start)!;
XmlAttribute id = person.getAttributeNode(":id")!;
print(id.key); // x:id
// id.namepace should be http://schemas.openxmlformats.org/package/2006/relationships
// it will lookup it ancestors and find first matched "xmlns:r" definition
print(id.namespace);
print(value); // 2
id.setAttribute("new value");
print(value); // new value
id.remove();
person.addAttribute("nattr")!;
print(person.containsAttribute("nattr")); // true
// you can get attributes map like this
Map<String,String> attrs = person.getAttributes();
节点缓存
如果你想持有一个节点
这是一个正确的用法示例
//root is defaultly mounted
var root = XmlDocument.root;
var person = doc.root
.into(type: XmlElementType.start)!
.mount(); // mounted
var info = doc.root
.next(selector: (n)=>n.type == XmlElementType.start && n.name == "info")!
.mount(); // mounted
person.addAttribute("nattr");
info.addAttribute("nattr");
person.unmount();// release
info.unmount();// release
return;
错误的用法
//root is defaultly mounted
var root = XmlDocument.root;
var person = doc.root
.into(type: XmlElementType.start)!
.mount(); // mounted
var info = doc.root
.next(selector: (n)=>n.type == XmlElementType.start && n.name == "info")!; // unmounted
person.addAttribute("nattr");
// after person node write action
// info node still keep the origin pointer, so it will write the attribute on wrong position
info.addAttribute("nattr");
person.unmount();// release
return;
节点写入
你可以使用以下方法添加、删除和复制节点
XmlNode.createnode.removenode.copy
所有写入操作都依赖于XmlNodeInstance对象
它具有以下方法
inst.pasteBeforeinst.pasteAfterinst.pasteInner
这里有一个关于如何创建新节点的示例
var root = XmlDocument.root;
var person = doc.root
.into(type: XmlElementType.start)!
.mount();
XmlNodeInstance inst = XmlNode.create("new");
var newNode = inst.pasteBefore(person).mount();
// xml will be changed like this
// <root>
// <new/> <-- new node will be add before person node
// <person/>
// ...
// </root>
你可以将节点复制到XmlNodeInstance对象
var root = XmlDocument.root;
var person = doc.root
.into(type: XmlElementType.start)!
.mount();
var info = doc.root
.next(selector: (n)=>n.type == XmlElementType.start && n.name == "info")!
.mount();
XmlNodeInstance copy = info.copy();
var newNode = inst.pasteInner(person).mount();
// xml will be changed like this
// <root>
// <person>
// <info> <-- copy to here
// <child/>
// </info>
// </person>
// ...
// </root>