use indexmap::IndexMap;
use smallvec::SmallVec;
use crate::namespace::Namespace;
pub type NodeId = usize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NodeType {
Document,
Element,
Text,
CData,
Comment,
ProcessingInstruction,
Attribute,
Namespace,
}
impl NodeType {
pub fn can_have_children(&self) -> bool {
matches!(self, NodeType::Document | NodeType::Element)
}
}
#[derive(Debug)]
pub(crate) struct NodeData {
pub id: NodeId,
pub node_type: NodeType,
pub name: String,
pub prefix: Option<String>,
pub namespace_uri: Option<String>,
pub content: Option<String>,
pub attributes: IndexMap<String, String>,
pub attribute_ns_info: IndexMap<String, (String, String)>,
pub namespace_decls: Vec<Namespace>,
pub parent: Option<NodeId>,
pub children: SmallVec<[NodeId; 4]>,
pub line: Option<usize>,
pub column: Option<usize>,
}
impl NodeData {
pub fn document() -> Self {
Self {
id: 0,
node_type: NodeType::Document,
name: String::new(),
prefix: None,
namespace_uri: None,
content: None,
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn element(
id: NodeId,
name: String,
prefix: Option<String>,
namespace_uri: Option<String>,
) -> Self {
Self {
id,
node_type: NodeType::Element,
name,
prefix,
namespace_uri,
content: None,
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn text(id: NodeId, content: String) -> Self {
Self {
id,
node_type: NodeType::Text,
name: String::new(),
prefix: None,
namespace_uri: None,
content: Some(content),
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn cdata(id: NodeId, content: String) -> Self {
Self {
id,
node_type: NodeType::CData,
name: String::new(),
prefix: None,
namespace_uri: None,
content: Some(content),
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn comment(id: NodeId, content: String) -> Self {
Self {
id,
node_type: NodeType::Comment,
name: String::new(),
prefix: None,
namespace_uri: None,
content: Some(content),
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn processing_instruction(id: NodeId, target: String, content: Option<String>) -> Self {
Self {
id,
node_type: NodeType::ProcessingInstruction,
name: target,
prefix: None,
namespace_uri: None,
content,
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn attribute(
id: NodeId,
name: String,
value: String,
prefix: Option<String>,
namespace_uri: Option<String>,
) -> Self {
Self {
id,
node_type: NodeType::Attribute,
name,
prefix,
namespace_uri,
content: Some(value),
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn namespace_node(id: NodeId, prefix: String, uri: String) -> Self {
Self {
id,
node_type: NodeType::Namespace,
name: prefix,
prefix: None,
namespace_uri: None,
content: Some(uri),
attributes: IndexMap::new(),
attribute_ns_info: IndexMap::new(),
namespace_decls: Vec::new(),
parent: None,
children: SmallVec::new(),
line: None,
column: None,
}
}
pub fn qname(&self) -> String {
match &self.prefix {
Some(p) if !p.is_empty() => format!("{}:{}", p, self.name),
_ => self.name.clone(),
}
}
}