use std::cell::{Cell, RefCell};
use std::error::Error;
use std::fmt;
use std::rc::{Rc, Weak};
use std::usize;
use sax::{SaxDecoder, XmlToken};
use xmlerror::*;
#[derive(Clone)]
pub struct NodePtr {
rc_node: RcNode,
}
type RcNode = Rc<Node>;
fn wrap_rc_clone(rc_node: &RcNode) -> NodePtr {
return NodePtr{ rc_node: Rc::clone(rc_node) };
}
impl fmt::Debug for NodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.node_type() {
NodeType::DocumentRoot => {
return write!(f, "(DocumentRoot)");
},
NodeType::Element => {
let mut str = String::new();
str += &"<";
str += &self.name();
for at in self.attributes().iter() {
str += &format!(r#" {}="{}""#, at.name(), at.value());
}
str += &">";
return write!(f, "{}", str);
},
NodeType::Text => {
return write!(f, "{}", self.value());
},
NodeType::Attribute => {
return write!(f, r#"{}="{}""#, self.name(), self.value());
},
_ => {
return write!(f, "");
},
}
}
}
impl fmt::Display for NodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
return write!(f, "{:?}", self);
}
}
impl PartialEq for NodePtr {
fn eq(&self, other: &NodePtr) -> bool {
return Rc::ptr_eq(&self.rc_node, &other.rc_node)
}
}
impl Eq for NodePtr {
}
#[derive(Debug, PartialEq, Clone)]
pub enum NodeType {
DocumentRoot,
Element,
Text,
Comment,
XMLDecl,
Instruction,
Attribute,
Directive,
}
#[derive(Debug)]
struct Node {
node_type: NodeType,
order: Cell<i64>,
name: String,
value: String,
parent: Option<RefCell<Weak<Node>>>,
children: RefCell<Vec<RcNode>>,
attributes: RefCell<Vec<RcNode>>,
}
fn make_new_rc_node(node_type: NodeType,
parent: Option<&mut RcNode>,
name: &str, value: &str) -> RcNode {
let node = Rc::new(Node {
node_type,
order: Cell::new(0),
name: String::from(name),
value: String::from(value),
parent: match parent {
Some(p) => Some(RefCell::new(Rc::downgrade(p))),
None => None,
},
children: RefCell::new(vec!{}),
attributes: RefCell::new(vec!{}),
});
return node;
}
fn make_new_child_rc_node(node_type: NodeType, parent: &mut RcNode,
name: &str, value: &str, index_hint: usize) -> RcNode {
let node = make_new_rc_node(node_type, Some(parent), name, value);
if index_hint <= parent.children.borrow_mut().len() {
parent.children.borrow_mut().insert(index_hint, Rc::clone(&node));
} else {
parent.children.borrow_mut().push(Rc::clone(&node));
}
return node;
}
pub fn new_document(xml_string: &str) -> Result<NodePtr, Box<Error>> {
let mut dec = SaxDecoder::new(&String::from(xml_string))?;
let doc_root = make_new_rc_node(NodeType::DocumentRoot, None, "", "");
let mut curr_node = Rc::clone(&doc_root);
loop {
match dec.raw_token() {
Ok(XmlToken::EOF) => {
break;
},
Ok(XmlToken::StartElement{name, attr}) => {
let e = make_new_child_rc_node(NodeType::Element,
&mut curr_node,
name.as_str(), "", usize::MAX);
curr_node = Rc::clone(&e);
for at in attr.iter() {
let attr_node = make_new_rc_node(NodeType::Attribute,
Some(&mut curr_node), at.name(), at.value());
curr_node.attributes.borrow_mut().push(
Rc::clone(&attr_node));
}
},
Ok(XmlToken::EndElement{name}) => {
if curr_node.name.as_str() != name {
return Err(xml_syntax_error!(
"Element name mismatch: {} and {}",
curr_node.name.as_str(), name));
}
curr_node = match curr_node.parent {
Some(ref p) => p.borrow().upgrade().unwrap(),
None => Rc::clone(&curr_node),
};
},
Ok(XmlToken::CharData{chardata}) => {
make_new_child_rc_node(NodeType::Text,
&mut curr_node,
"", chardata.as_str(), usize::MAX);
},
Ok(XmlToken::ProcInst{target, inst}) => {
if target == "xml" {
make_new_child_rc_node(NodeType::XMLDecl,
&mut curr_node,
"xml", inst.as_str(), usize::MAX);
} else {
make_new_child_rc_node(NodeType::Instruction,
&mut curr_node,
target.as_str(), inst.as_str(), usize::MAX);
}
},
Ok(XmlToken::Comment{comment}) => {
make_new_child_rc_node(NodeType::Comment,
&mut curr_node,
"", comment.as_str(), usize::MAX);
},
Ok(XmlToken::Directive{directive: _directive}) => {},
Err(e) => {
return Err(xml_syntax_error!("XML syntax error: {}", e));
},
}
}
return Ok(NodePtr{rc_node: doc_root});
}
fn shallow_copy_rc_rels(target: &mut RcNode, source: &RcNode) {
for ch in source.children.borrow().iter() {
target.children.borrow_mut().push(Rc::clone(ch));
}
for at in source.attributes.borrow().iter() {
target.attributes.borrow_mut().push(Rc::clone(at));
}
}
impl NodePtr {
pub fn to_string(&self) -> String {
return to_string_with_indent(&self.unwrap_rc(), 0, 0);
}
pub fn to_pretty_string(&self) -> String {
return to_string_with_indent(&self.unwrap_rc(), 0, 4);
}
pub fn inner_xml(&self) -> String {
let mut s = String::new();
for ch in self.children().iter() {
s += &ch.to_string();
}
return s;
}
pub fn node_type(&self) -> NodeType {
return self.unwrap_rc().node_type.clone();
}
pub fn name(&self) -> String {
return self.unwrap_rc().name.clone();
}
pub fn value(&self) -> String {
return self.unwrap_rc().value.clone();
}
pub fn local_name(&self) -> String {
let name = &self.unwrap_rc().name;
let v: Vec<&str> = name.splitn(2, ":").collect();
if v.len() == 2 {
return String::from(v[1]);
} else {
return name.clone();
}
}
pub fn space_name(&self) -> String {
let name = &self.unwrap_rc().name;
let v: Vec<&str> = name.splitn(2, ":").collect();
if v.len() == 2 {
return String::from(v[0]);
} else {
return String::new();
}
}
pub fn namespace_uri(&self) -> String {
let mut xmlns_attr = String::from("xmlns");
let space = self.space_name();
if space.as_str() != "" {
xmlns_attr += &":";
xmlns_attr += &space;
}
let mut curr = self.unwrap_rc();
while (*curr).node_type != NodeType::DocumentRoot {
let val = wrap_rc_clone(&curr).attribute_value(xmlns_attr.as_str());
if let Some(value) = val {
return value.clone();
}
curr = match (*curr).parent {
Some(ref p) => p.borrow().upgrade().unwrap(),
None => return String::new(),
};
}
return String::new();
}
pub fn root(&self) -> NodePtr {
let mut curr = self.unwrap_rc();
loop {
curr = match (*curr).parent {
Some(ref p) => p.borrow().upgrade().unwrap(),
None => return wrap_rc_clone(&curr),
};
}
}
pub fn root_element(&self) -> NodePtr {
let doc_root = self.root();
for ch in doc_root.children().iter() {
if ch.node_type() == NodeType::Element {
return ch.clone();
}
}
return doc_root;
}
pub fn parent(&self) -> Option<NodePtr> {
match self.unwrap_rc().parent {
Some(ref p) => {
let parent_node = p.borrow().upgrade().unwrap();
return Some(wrap_rc_clone(&parent_node));
},
None => return None,
}
}
pub fn children(&self) -> Vec<NodePtr> {
let mut node_array: Vec<NodePtr> = vec!{};
let rc_node = self.unwrap_rc();
for ch in (*rc_node).children.borrow().iter() {
node_array.push(wrap_rc_clone(ch));
}
return node_array;
}
pub fn attributes(&self) -> Vec<NodePtr> {
let mut node_array: Vec<NodePtr> = vec!{};
let rc_node = self.unwrap_rc();
for at in (*rc_node).attributes.borrow().iter() {
node_array.push(wrap_rc_clone(at));
}
return node_array;
}
pub fn first_child(&self) -> Option<NodePtr> {
return self.nth_child(0);
}
pub fn nth_child(&self, n: usize) -> Option<NodePtr> {
let rc_node = self.unwrap_rc();
if n < rc_node.children.borrow().len() {
return Some(wrap_rc_clone(&(*rc_node).children.borrow()[n]));
} else {
return None
}
}
pub fn append_child(&self, new_child: &NodePtr) {
let rc_self = self.unwrap_rc();
let rc_new_child = new_child.unwrap_rc();
rc_self.children.borrow_mut().push(Rc::clone(&rc_new_child));
self.clear_document_order();
}
pub fn insert_as_previous_sibling(&self, new_node: &NodePtr) {
let parent = match self.parent() {
Some(p) => p,
None => return,
};
let n = parent.find_child_index(self);
if n != usize::MAX {
let mut rc_parent = parent.unwrap_rc();
let rc_new_node = new_node.unwrap_rc();
let mut rc_new_node_dup = make_new_child_rc_node(
rc_new_node.node_type.clone(),
&mut rc_parent,
&rc_new_node.name,
&rc_new_node.value,
n);
shallow_copy_rc_rels(&mut rc_new_node_dup, &rc_new_node);
}
self.clear_document_order();
}
pub fn insert_as_next_sibling(&self, new_node: &NodePtr) {
let parent = match self.parent() {
Some(p) => p,
None => return,
};
let n = parent.find_child_index(self);
if n != usize::MAX {
let mut rc_parent = parent.unwrap_rc();
let rc_new_node = new_node.unwrap_rc();
let mut rc_new_node_dup = make_new_child_rc_node(
rc_new_node.node_type.clone(),
&mut rc_parent,
&rc_new_node.name,
&rc_new_node.value,
n + 1);
shallow_copy_rc_rels(&mut rc_new_node_dup, &rc_new_node);
}
self.clear_document_order();
}
pub fn delete_child(&self, target: &NodePtr) {
let n = self.find_child_index(target);
if n != usize::MAX {
let rc_node = self.unwrap_rc();
(*rc_node).children.borrow_mut().remove(n);
}
self.clear_document_order();
}
pub fn replace_with(&self, new_node: &NodePtr) {
let parent = match self.parent() {
Some(p) => p,
None => return,
};
self.insert_as_previous_sibling(new_node);
parent.delete_child(self);
self.clear_document_order();
}
fn find_child_index(&self, target: &NodePtr) -> usize {
let rc_node = self.unwrap_rc();
let target_node = target.unwrap_rc();
for (i, ch) in (*rc_node).children.borrow().iter().enumerate() {
if Rc::ptr_eq(ch, &target_node) {
return i;
}
}
return usize::MAX;
}
pub fn attribute_value(&self, name: &str) -> Option<String> {
let r_index = self.find_attribute_index(name);
if r_index != usize::MAX {
let rc_node = self.unwrap_rc();
return Some((*rc_node).attributes.borrow()[r_index].value.clone());
} else {
return None;
}
}
pub fn set_attribute(&mut self, name: &str, value: &str) {
let mut rc_node = self.unwrap_rc();
let attr_node = make_new_rc_node(NodeType::Attribute,
Some(&mut rc_node), name, value);
let r_index = self.find_attribute_index(name);
if r_index != usize::MAX {
(*rc_node).attributes.borrow_mut().remove(r_index);
(*rc_node).attributes.borrow_mut().insert(r_index, Rc::clone(&attr_node));
} else {
(*rc_node).attributes.borrow_mut().push(Rc::clone(&attr_node));
}
self.clear_document_order();
}
pub fn delete_attribute(&mut self, name: &str) {
let r_index = self.find_attribute_index(name);
if r_index != usize::MAX {
let rc_node = self.unwrap_rc();
(*rc_node).attributes.borrow_mut().remove(r_index);
}
self.clear_document_order();
}
fn find_attribute_index(&self, name: &str) -> usize {
let rc_node = self.unwrap_rc();
for (i, at) in (*rc_node).attributes.borrow().iter().enumerate() {
if at.name == name {
return i;
}
}
return usize::MAX;
}
fn clear_document_order(&self) {
let root = self.root();
root.unwrap_rc().order.set(0);
}
pub fn document_order(&self) -> i64 {
let root = self.root();
if root.unwrap_rc().order.get() == 0 {
root.setup_document_order();
}
return self.unwrap_rc().order.get();
}
fn setup_document_order(&self) {
self.setup_document_order_sub(1);
}
fn setup_document_order_sub(&self, order_beg: i64) -> i64 {
let mut order = order_beg;
self.unwrap_rc().order.set(order);
order += 1;
for at in self.attributes().iter() {
at.unwrap_rc().order.set(order);
order += 1;
}
for ch in self.children().iter() {
order = ch.setup_document_order_sub(order + 1);
}
return order;
}
pub fn rc_clone(&self) -> NodePtr {
return NodePtr {
rc_node: Rc::clone(&self.rc_node),
};
}
fn unwrap_rc(&self) -> RcNode {
return Rc::clone(&self.rc_node);
}
}
fn to_string_with_indent(rc_node: &RcNode, indent: usize, step: usize) -> String {
match rc_node.node_type {
NodeType::DocumentRoot => {
let mut s = String::new();
for ch in rc_node.children.borrow().iter() {
s += &to_string_with_indent(ch, indent, step);
}
return s;
},
NodeType::Element => {
let mut s = String::new();
s += &format!("{}<{}", " ".repeat(indent), rc_node.name);
for at in rc_node.attributes.borrow().iter() {
s += &format!(r#" {}="{}""#,
at.name, encode_entity(&at.value));
}
if rc_node.children.borrow().len() == 0 {
s += &"/>";
} else {
s += &">";
s += &nl_if_positive(step);
for ch in rc_node.children.borrow().iter() {
s += &to_string_with_indent(ch, indent + step, step);
}
s += &format!("{}</{}>", " ".repeat(indent), rc_node.name);
}
s += &nl_if_positive(step);
return s;
},
NodeType::Text => {
return format!("{}{}{}",
&" ".repeat(indent),
&encode_entity(&(rc_node.value)),
&nl_if_positive(step));
},
NodeType::Comment => {
return format!("{}<!--{}-->{}",
&" ".repeat(indent),
&rc_node.value,
&nl_if_positive(step));
},
NodeType::XMLDecl => {
return format!("{}<?xml {}?>{}",
&" ".repeat(indent),
&rc_node.value,
&nl_if_positive(step));
},
NodeType::Instruction => {
return format!("{}<?{} {}?>{}",
&" ".repeat(indent),
&rc_node.name,
&rc_node.value,
&nl_if_positive(step));
},
_ => return String::new(),
}
}
fn encode_entity(s: &String) -> String {
let specs = [
[ "&", "&" ],
[ ">", ">" ],
[ "<", "<" ],
[ "\"", """ ],
[ "'", "'" ],
];
let mut str = s.clone();
for spec in specs.iter() {
str = str.replace(spec[0], spec[1]);
}
return str
}
fn nl_if_positive<'a>(n: usize) -> &'a str {
return if 0 < n { "\n" } else { "" };
}