逆引き風 roxmltree の基礎的な使い方のメモ; rust のたぶん今の所いちばん速くて安全な XML ぱーさー
- https://crates.io/crates/roxmltree/
- https://github.com/RazrFalcon/roxmltree/
- https://docs.rs/roxmltree/0.13.0/roxmltree/
note: このメモは roxmltree-0.13.0 の時代に書きました。
はじめに知っておくとよいこと
- 与えられた XML ≈
Document
をNode
の木構造に分解してNode
を基準に操作するための crate =roxmltree
Node
は XML の Element (≈タグ)とは限りません。Node
が出てきたらカモシレナイ match/if が必要なパターンがありますancestor
は上位(先祖)、sbling
は同位(姉妹)、descendant
は下位(子孫)parent
は直近の上位(親)、child
は直近の下位(子)
XMLを開く
let document: roxmltree::Document = roxmltree::Document::parse( "<root/>" );
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Document.html#method.parse
- note: ここから先で
document
が出てきたらこの続きと思って下さい。
XMLのルート要素の Node
を取得する
let node: roxmltree::Node = d.root_element();
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Document.html#method.root_element
- note:
.root()
はドキュメントそのもの的なNode
が帰ってきます。 - note: ここから先で
node
が出てきたらroxmltree::Node
な変数だと思って下さい。
Node
が Element なのか何なのか確認する
match node.node_type() { roxmltree::NodeType::Element => println!("This Node is an Element."), _ => println!("This Node is NOT an Element.") }
または
let is_element: bool = node.is_element(); let is_comment: bool = node.is_comment();
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.node_type
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.is_root
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.is_element
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.is_pi
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.is_comment
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.is_text
Element な Node
のタグ名を確認または取得する
// <xxx> か判定 let is_xxx_tag: bool = node.has_tag_name("xxx"); // タグ名を取得 let tag_name: roxmltree::ExpandedName = node.tag_name(); // タグ名のローカル名部分を取得; <abbrns:localpart> の localpart の部分 let tag_local_name: &str = tag_name.name(); // タグ名の名前空間部分を取得; <abbrns:localpart> の abbrns の部分の xmlns: 定義の uri 値 let tag_namespace: &str = tag_name.namespace();
- note:
ExpandedName
の.namespace()
は<abbrns:localname>
に対してabbrns
ではなくxmlns:abbrns="http://example.com/"
を解決したhttp://example.com/
を取得します。 - https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.has_tag_name
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.tag_name
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.ExpandedName.html
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.ExpandedName.html#method.name
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.ExpandedName.html#method.namespace
XML Namespace 群を確認する
for ns: &roxmltree::Namespace in document.root_element().namespace() { println!("name={:?} uri={}", ns.name(), ns.uri()); }
- Note: 任意の
Node
で実装できますが、実際に XML でxmlns:
群が定義されている Element なNode
じゃないと何も出てきません。 - https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.namespaces
Node
の Attribute 群を取得する
for attribute: &roxmltree::Attribute in node.attributes() { println!("name={} value={}", attribute.name(), attribute.value()); }
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.attributes
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Attribute.html
Node
の直近の下位(子) Element な Node
群を取得、または同位(姉妹)の Node
群を取得など
// 手法 A; .children から Element を .filter let child_elements = document.root_element().children().filter(|n|n.node_type()==roxmltree::NodeType::Element); for node: roxmltree::Node in child_elements { println!("name={} text={:?}", node.tag_name().name(), node.text() ); }
// 手法 B; .first_element_child から Option を while して .next_sibling_element let mut node_maybe = document.root_element().first_element_child(); while let Some(node) = node_maybe { println!("name={} text={:?}", node.tag_name().name(), node.text() ); node_maybe = node.next_sibling_element(); }
- 残念ながら
Node
に.element_children
的な関数はいまのところ無いので.children
から.filter
します。 - https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.children
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.first_element_child
Node
の上位(先祖)群、直近の上位(親)、下位(子孫)群
// 上位群 let ancentors: AxisIter = node.ancestors(); for node: roxmltree::Node in ancentors { println!("ancentor name={} text={:?}", node.tag_name().name(), node.text() ); } // 直近の上位 let parent_maybe: Option<roxmltree::Node> = node.parent_element(); let node: roxmltree::Node = parent_maybe.unwrap(); println!("parent name={} text={:?}", node.tag_name().name(), node.text() ); // 下位群 let descendants: Descendants = node.descendants(); for node: roxmltree::Node in descendants { println!("descendant name={} text={:?}", node.tag_name().name(), node.text() ); }
AxisIter
≈ [.parent()
,.parent().parent()
->.parent().parent().parent()
, .. ] 的に列挙してくれるやつDescendants
≈ 再帰的に.children
で下位Node
を根こそぎして.flatten
したような、下位Node
すべてがごそっと取り出せるやつ- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.ancestors
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.parent_element
- https://docs.rs/roxmltree/0.13.0/roxmltree/struct.Node.html#method.descendants