use std::sync::Arc;
use indexmap::IndexMap;
use parking_lot::RwLock;
use crate::namespace::Namespace;
use super::types::{NodeData, NodeId, NodeType};
#[derive(Clone)]
pub struct XmlNode {
pub(crate) id: NodeId,
pub(crate) nodes: Arc<RwLock<Vec<NodeData>>>,
}
impl XmlNode {
pub fn id(&self) -> NodeId {
self.id
}
pub fn get_type(&self) -> NodeType {
let nodes = self.nodes.read();
nodes
.get(self.id)
.map(|n| n.node_type)
.unwrap_or(NodeType::Document)
}
pub fn get_name(&self) -> String {
let nodes = self.nodes.read();
nodes
.get(self.id)
.map(|n| n.name.clone())
.unwrap_or_default()
}
pub fn get_prefix(&self) -> Option<String> {
let nodes = self.nodes.read();
nodes.get(self.id).and_then(|n| n.prefix.clone())
}
pub fn get_namespace_uri(&self) -> Option<String> {
let nodes = self.nodes.read();
nodes.get(self.id).and_then(|n| n.namespace_uri.clone())
}
pub fn get_namespace(&self) -> Option<Namespace> {
let nodes = self.nodes.read();
nodes.get(self.id).and_then(|n| {
n.namespace_uri
.as_ref()
.map(|uri| Namespace::new(n.prefix.clone().unwrap_or_default(), uri.clone()))
})
}
pub fn qname(&self) -> String {
let nodes = self.nodes.read();
nodes.get(self.id).map(|n| n.qname()).unwrap_or_default()
}
pub fn get_content(&self) -> Option<String> {
let nodes = self.nodes.read();
let node = nodes.get(self.id)?;
match node.node_type {
NodeType::Text
| NodeType::CData
| NodeType::Comment
| NodeType::Attribute
| NodeType::Namespace => node.content.clone(),
NodeType::Element => {
let mut content = String::new();
self.collect_text_content_recursive(node.id, &nodes, &mut content);
if content.is_empty() {
None
} else {
Some(content)
}
}
_ => None,
}
}
fn collect_text_content_recursive(
&self,
node_id: NodeId,
nodes: &[NodeData],
content: &mut String,
) {
if let Some(node) = nodes.get(node_id) {
match node.node_type {
NodeType::Text | NodeType::CData => {
if let Some(ref text) = node.content {
content.push_str(text);
}
}
NodeType::Element => {
for &child_id in &node.children {
self.collect_text_content_recursive(child_id, nodes, content);
}
}
_ => {}
}
}
}
pub fn get_attribute(&self, name: &str) -> Option<String> {
let nodes = self.nodes.read();
nodes
.get(self.id)
.and_then(|n| n.attributes.get(name).cloned())
}
pub fn get_attribute_ns(&self, name: &str, ns_uri: &str) -> Option<String> {
let nodes = self.nodes.read();
let node = nodes.get(self.id)?;
if let Some(value) = node.attributes.get(name) {
return Some(value.clone());
}
for ns in &node.namespace_decls {
if ns.uri() == ns_uri {
let prefixed_name = format!("{}:{}", ns.prefix(), name);
if let Some(value) = node.attributes.get(&prefixed_name) {
return Some(value.clone());
}
}
}
None
}
pub fn get_attributes(&self) -> IndexMap<String, String> {
let nodes = self.nodes.read();
nodes
.get(self.id)
.map(|n| n.attributes.clone())
.unwrap_or_default()
}
pub fn get_attribute_ns_info(&self, local_name: &str) -> Option<(String, String)> {
let nodes = self.nodes.read();
nodes
.get(self.id)
.and_then(|n| n.attribute_ns_info.get(local_name).cloned())
}
pub fn get_namespace_declarations(&self) -> Vec<Namespace> {
let nodes = self.nodes.read();
nodes
.get(self.id)
.map(|n| n.namespace_decls.clone())
.unwrap_or_default()
}
pub fn get_parent(&self) -> Option<XmlNode> {
let nodes = self.nodes.read();
let parent_id = nodes.get(self.id)?.parent?;
Some(XmlNode {
id: parent_id,
nodes: Arc::clone(&self.nodes),
})
}
pub fn get_child_nodes(&self) -> Vec<XmlNode> {
let nodes = self.nodes.read();
nodes
.get(self.id)
.map(|n| {
n.children
.iter()
.map(|&id| XmlNode {
id,
nodes: Arc::clone(&self.nodes),
})
.collect()
})
.unwrap_or_default()
}
pub fn get_child_elements(&self) -> Vec<XmlNode> {
let nodes = self.nodes.read();
nodes
.get(self.id)
.map(|n| {
n.children
.iter()
.filter_map(|&id| {
nodes.get(id).and_then(|child| {
if child.node_type == NodeType::Element {
Some(XmlNode {
id,
nodes: Arc::clone(&self.nodes),
})
} else {
None
}
})
})
.collect()
})
.unwrap_or_default()
}
pub fn first_child(&self) -> Option<XmlNode> {
let nodes = self.nodes.read();
let node = nodes.get(self.id)?;
node.children.first().map(|&id| XmlNode {
id,
nodes: Arc::clone(&self.nodes),
})
}
pub fn last_child(&self) -> Option<XmlNode> {
let nodes = self.nodes.read();
let node = nodes.get(self.id)?;
node.children.last().map(|&id| XmlNode {
id,
nodes: Arc::clone(&self.nodes),
})
}
pub fn line(&self) -> Option<usize> {
let nodes = self.nodes.read();
nodes.get(self.id).and_then(|n| n.line)
}
pub fn column(&self) -> Option<usize> {
let nodes = self.nodes.read();
nodes.get(self.id).and_then(|n| n.column)
}
pub fn set_attribute(&self, name: &str, value: &str) {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
node.attributes.insert(name.to_string(), value.to_string());
}
}
pub fn remove_attribute(&self, name: &str) -> Option<String> {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
return node.attributes.shift_remove(name);
}
None
}
pub fn set_content(&self, content: &str) {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
match node.node_type {
NodeType::Text | NodeType::CData | NodeType::Comment => {
node.content = Some(content.to_string());
}
NodeType::Element => {
node.children.clear();
node.content = Some(content.to_string());
}
_ => {}
}
}
}
pub fn set_name(&self, name: &str) {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
node.name = name.to_string();
}
}
pub fn set_prefix(&self, prefix: Option<&str>) {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
node.prefix = prefix.map(|s| s.to_string());
}
}
pub fn set_namespace_uri(&self, uri: Option<&str>) {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
node.namespace_uri = uri.map(|s| s.to_string());
}
}
pub fn add_namespace_decl(&self, prefix: &str, uri: &str) {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
node.namespace_decls
.push(Namespace::new(prefix.to_string(), uri.to_string()));
}
}
pub fn clear_children(&self) {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(self.id) {
node.children.clear();
}
}
pub fn is_element(&self) -> bool {
self.get_type() == NodeType::Element
}
pub fn is_text(&self) -> bool {
self.get_type() == NodeType::Text
}
}
impl std::fmt::Debug for XmlNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("XmlNode")
.field("id", &self.id)
.field("type", &self.get_type())
.field("name", &self.get_name())
.finish()
}
}
impl PartialEq for XmlNode {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && Arc::ptr_eq(&self.nodes, &other.nodes)
}
}
impl Eq for XmlNode {}
impl std::hash::Hash for XmlNode {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
Arc::as_ptr(&self.nodes).hash(state);
}
}