pub mod roxmltree;
pub use self::roxmltree::RoXmlNavigator;
use crate::ids::SimpleTypeKey;
use crate::types::value::XmlValue;
#[derive(Debug, Clone, thiserror::Error)]
pub enum NavigatorError {
#[error("{0}")]
Other(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum TypedValue {
Value(XmlValue),
Untyped,
Nilled,
Absent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DomNodeType {
Root,
Element,
Attribute,
Namespace,
Text,
Whitespace,
SignificantWhitespace,
Comment,
ProcessingInstruction,
All,
}
impl DomNodeType {
pub fn is_text_like(self) -> bool {
matches!(
self,
DomNodeType::Text | DomNodeType::Whitespace | DomNodeType::SignificantWhitespace
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum XmlNodeOrder {
Before,
After,
Same,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NamespaceAxisScope {
All,
Local,
ExcludeXml,
}
pub trait DomNavigator: Clone {
fn is_same_position(&self, other: &Self) -> bool;
fn compare_position(&self, other: &Self) -> XmlNodeOrder;
fn move_to(&mut self, other: &Self) -> bool;
fn move_to_root(&mut self);
fn move_to_visible_root(&mut self) {
self.move_to_root();
}
fn move_to_parent(&mut self) -> bool;
fn move_to_first_child(&mut self) -> bool;
fn move_to_next_sibling(&mut self) -> bool;
fn move_to_prev_sibling(&mut self) -> bool;
fn move_to_first_attribute(&mut self) -> bool;
fn move_to_next_attribute(&mut self) -> bool;
fn move_to_first_namespace(&mut self, scope: NamespaceAxisScope) -> bool;
fn move_to_next_namespace(&mut self, scope: NamespaceAxisScope) -> bool;
fn move_to_following(&mut self, kind: DomNodeType, end: Option<&Self>) -> bool;
fn node_type(&self) -> DomNodeType;
fn local_name(&self) -> &str;
fn name(&self) -> &str;
fn namespace_uri(&self) -> &str;
fn prefix(&self) -> &str;
fn value(&self) -> String;
fn base_uri(&self) -> &str;
fn schema_type(&self) -> Option<SimpleTypeKey>;
fn typed_value(&self) -> TypedValue;
fn has_attributes(&mut self) -> bool {
let ok = self.move_to_first_attribute();
if ok {
self.move_to_parent();
}
ok
}
fn has_children(&mut self) -> bool {
let ok = self.move_to_first_child();
if ok {
self.move_to_parent();
}
ok
}
fn move_to_child_kind(&mut self, kind: DomNodeType) -> bool {
if self.move_to_first_child() {
loop {
if self.node_type() == kind || kind == DomNodeType::All {
return true;
}
if !self.move_to_next_sibling() {
break;
}
}
self.move_to_parent();
}
false
}
fn move_to_child_name(&mut self, local: &str, ns: &str) -> bool {
if self.move_to_first_child() {
loop {
if self.node_type() == DomNodeType::Element
&& self.local_name() == local
&& self.namespace_uri() == ns
{
return true;
}
if !self.move_to_next_sibling() {
break;
}
}
self.move_to_parent();
}
false
}
fn find_element_by_id(&self, id: &str) -> Result<Option<Self>, NavigatorError> {
let _ = id;
Ok(None)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dom_node_type_equality() {
assert_eq!(DomNodeType::Element, DomNodeType::Element);
assert_ne!(DomNodeType::Element, DomNodeType::Attribute);
}
#[test]
fn test_dom_node_type_is_text_like() {
assert!(DomNodeType::Text.is_text_like());
assert!(DomNodeType::Whitespace.is_text_like());
assert!(DomNodeType::SignificantWhitespace.is_text_like());
assert!(!DomNodeType::Element.is_text_like());
assert!(!DomNodeType::Attribute.is_text_like());
assert!(!DomNodeType::Comment.is_text_like());
}
#[test]
fn test_xml_node_order() {
assert_ne!(XmlNodeOrder::Before, XmlNodeOrder::After);
assert_eq!(XmlNodeOrder::Same, XmlNodeOrder::Same);
}
#[test]
fn test_namespace_axis_scope() {
assert_ne!(NamespaceAxisScope::All, NamespaceAxisScope::Local);
assert_eq!(
NamespaceAxisScope::ExcludeXml,
NamespaceAxisScope::ExcludeXml
);
}
}