mod builder;
mod reference;
mod serialize;
mod types;
mod xpath;
use std::collections::HashMap;
use indexmap::IndexMap;
use crate::document::XmlDocument;
use crate::node::{NodeId, XmlNode};
pub use builder::EditableNodeBuilder;
pub use reference::EditableNodeRef;
pub use types::{Modification, NewNode};
pub struct EditableNode {
pub(crate) doc: XmlDocument,
root_id: NodeId,
modifications: Vec<Modification>,
removed: bool,
pub(crate) namespaces: HashMap<String, String>,
}
impl EditableNode {
pub(crate) fn new(doc: XmlDocument, root_id: NodeId) -> Self {
Self {
doc,
root_id,
modifications: Vec::new(),
removed: false,
namespaces: HashMap::new(),
}
}
pub(crate) fn with_namespaces(
doc: XmlDocument,
root_id: NodeId,
namespaces: HashMap<String, String>,
) -> Self {
Self {
doc,
root_id,
modifications: Vec::new(),
removed: false,
namespaces,
}
}
pub fn name(&self) -> String {
self.root_node().get_name()
}
pub fn qname(&self) -> String {
self.root_node().qname()
}
pub fn prefix(&self) -> Option<String> {
self.root_node().get_prefix()
}
pub fn namespace_uri(&self) -> Option<String> {
self.root_node().get_namespace_uri()
}
pub fn get_attribute(&self, name: &str) -> Option<String> {
self.root_node().get_attribute(name)
}
pub fn get_attributes(&self) -> IndexMap<String, String> {
self.root_node().get_attributes()
}
pub fn get_content(&self) -> Option<String> {
self.root_node().get_content()
}
pub fn children(&self) -> Vec<EditableNodeRef<'_>> {
self.root_node()
.get_child_elements()
.into_iter()
.map(|node| EditableNodeRef {
node,
doc: &self.doc,
})
.collect()
}
pub fn child_nodes(&self) -> Vec<EditableNodeRef<'_>> {
self.root_node()
.get_child_nodes()
.into_iter()
.map(|node| EditableNodeRef {
node,
doc: &self.doc,
})
.collect()
}
pub fn set_attribute(&mut self, name: &str, value: &str) {
self.root_node().set_attribute(name, value);
self.modifications.push(Modification::SetAttribute {
name: name.to_string(),
value: value.to_string(),
});
}
pub fn remove_attribute(&mut self, name: &str) {
self.root_node().remove_attribute(name);
self.modifications.push(Modification::RemoveAttribute {
name: name.to_string(),
});
}
pub fn set_text_content(&mut self, text: &str) {
self.root_node().set_content(text);
self.modifications
.push(Modification::SetTextContent(text.to_string()));
}
pub fn append_child(&mut self, node: NewNode) {
self.modifications.push(Modification::AppendChild(node));
}
pub fn prepend_child(&mut self, node: NewNode) {
self.modifications.push(Modification::PrependChild(node));
}
pub fn replace_text(&mut self, old: &str, new: &str) {
self.modifications.push(Modification::ReplaceText {
old: old.to_string(),
new: new.to_string(),
});
}
pub fn remove(&mut self) {
self.removed = true;
}
pub fn is_removed(&self) -> bool {
self.removed
}
pub fn is_modified(&self) -> bool {
!self.modifications.is_empty() || self.removed
}
pub fn modifications(&self) -> &[Modification] {
&self.modifications
}
pub fn document(&self) -> &XmlDocument {
&self.doc
}
pub fn document_mut(&mut self) -> &mut XmlDocument {
&mut self.doc
}
pub(crate) fn root_node(&self) -> XmlNode {
self.doc.get_node(self.root_id).expect("root node exists")
}
}
#[cfg(test)]
mod tests;