use crate::externals::URLResolver;
use crate::item::{Node as ItemNode, NodeType};
use crate::output::OutputDefinition;
use crate::parser::xml::parse;
use crate::parser::ParserConfig;
use crate::qname::QualifiedName;
use crate::value::Value;
use crate::xdmerror::*;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_map::IntoIter;
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::rc::{Rc, Weak};
#[derive(Clone, Default)]
pub struct Document {
pub xmldecl: Option<XMLDecl>,
pub prologue: Vec<RNode>,
pub content: Vec<RNode>,
pub epilogue: Vec<RNode>,
}
impl Document {
fn new() -> Self {
Document {
..Default::default()
}
}
pub fn set_xmldecl(&mut self, x: XMLDecl) {
self.xmldecl = Some(x)
}
pub fn get_xmldecl(&self) -> &Option<XMLDecl> {
&self.xmldecl
}
pub fn push_content(&mut self, n: RNode) {
self.content.push(n)
}
pub fn to_xml(&self) -> String {
let mut result = String::new();
self.content
.iter()
.for_each(|c| result.push_str(c.to_xml().as_str()));
result
}
pub fn canonical(self) -> Document {
let d = match self.xmldecl {
None => XMLDecl {
version: "1.0".to_string(),
encoding: Some("UTF-8".to_string()),
standalone: None,
},
Some(x) => XMLDecl {
version: x.version,
encoding: Some("UTF-8".to_string()),
standalone: None,
},
};
let mut p = vec![];
for pn in self.prologue {
if let Ok(pcn) = pn.get_canonical() {
p.push(pcn)
}
}
let mut c = vec![];
for cn in self.content {
if let Ok(ccn) = cn.get_canonical() {
c.push(ccn)
}
}
let mut e = vec![];
for en in self.epilogue {
if let Ok(ecn) = en.get_canonical() {
e.push(ecn)
}
}
Document {
xmldecl: Some(d),
prologue: p,
content: c,
epilogue: e,
}
}
}
impl TryFrom<(String, Option<URLResolver>, Option<String>)> for Document {
type Error = Error;
fn try_from(s: (String, Option<URLResolver>, Option<String>)) -> Result<Self, Self::Error> {
let mut pc = ParserConfig::new();
pc.ext_dtd_resolver = s.1;
pc.docloc = s.2;
let doc = NodeBuilder::new(NodeType::Document).build();
parse(doc.clone(), s.0.as_str(), Some(pc))?;
let result = DocumentBuilder::new().content(vec![doc]).build();
Ok(result)
}
}
impl TryFrom<(&str, Option<URLResolver>, Option<String>)> for Document {
type Error = Error;
fn try_from(s: (&str, Option<URLResolver>, Option<String>)) -> Result<Self, Self::Error> {
let mut pc = ParserConfig::new();
pc.ext_dtd_resolver = s.1;
pc.docloc = s.2;
let doc = NodeBuilder::new(NodeType::Document).build();
parse(doc.clone(), s.0, Some(pc))?;
let result = DocumentBuilder::new().content(vec![doc]).build();
Ok(result)
}
}
impl PartialEq for Document {
fn eq(&self, other: &Document) -> bool {
self.xmldecl == other.xmldecl
&& self
.content
.iter()
.zip(other.content.iter())
.fold(true, |acc, (a, b)| acc && a == b)
}
}
impl PartialEq for Node {
fn eq(&self, other: &Node) -> bool {
self.node_type == other.node_type
&& self.name == other.name
&& self.value == other.value
&& self
.children
.borrow()
.iter()
.zip(other.children.borrow().iter())
.fold(true, |acc, (a, b)| acc && a == b)
}
}
pub struct DocumentBuilder(Document);
impl Default for DocumentBuilder {
fn default() -> Self {
Self::new()
}
}
impl DocumentBuilder {
pub fn new() -> Self {
DocumentBuilder(Document::new())
}
pub fn xmldecl(mut self, x: XMLDecl) -> Self {
self.0.xmldecl = Some(x);
self
}
pub fn prologue(mut self, p: Vec<RNode>) -> Self {
self.0.prologue = p;
self
}
pub fn content(mut self, p: Vec<RNode>) -> Self {
self.0.content = p;
self
}
pub fn epilogue(mut self, p: Vec<RNode>) -> Self {
self.0.epilogue = p;
self
}
pub fn build(self) -> Document {
self.0
}
}
#[derive(Clone, Default)]
pub struct Node {
node_type: NodeType,
parent: RefCell<Option<Weak<Node>>>,
children: RefCell<Vec<RNode>>,
attributes: RefCell<HashMap<QualifiedName, RNode>>,
name: RefCell<Option<QualifiedName>>,
value: Option<Rc<Value>>,
pi_name: Option<String>,
dtd: Option<DTD>,
reference: Option<QualifiedName>,
}
impl Node {
pub fn new(n: NodeType) -> Self {
Node {
node_type: n,
parent: RefCell::new(None),
children: RefCell::new(vec![]),
attributes: RefCell::new(HashMap::new()),
..Default::default()
}
}
pub fn pi_name(&self) -> Option<String> {
self.pi_name.clone()
}
pub fn reference(&self) -> Option<QualifiedName> {
self.reference.clone()
}
pub fn set_nsuri(&self, uri: String) {
let new = match &*self.name.borrow() {
Some(old) => QualifiedName::new(Some(uri), old.get_prefix(), old.get_localname()),
None => panic!("no node name"),
};
let _ = self.name.borrow_mut().insert(new);
}
}
pub type RNode = Rc<Node>;
impl ItemNode for RNode {
type NodeIterator = Box<dyn Iterator<Item = RNode>>;
fn node_type(&self) -> NodeType {
self.node_type
}
fn name(&self) -> QualifiedName {
self.name
.borrow()
.as_ref()
.map_or(QualifiedName::new(None, None, String::new()), |n| n.clone())
}
fn value(&self) -> Rc<Value> {
self.value
.as_ref()
.map_or(Rc::new(Value::from("")), |v| v.clone())
}
fn get_id(&self) -> String {
format!("{:p}", &**self as *const Node)
}
fn to_string(&self) -> String {
match self.node_type() {
NodeType::Document | NodeType::Element => self
.descend_iter()
.filter(|c| c.node_type() == NodeType::Text)
.fold(String::new(), |mut acc, c| {
acc.push_str(c.to_string().as_str());
acc
}),
NodeType::Text
| NodeType::Attribute
| NodeType::Comment
| NodeType::ProcessingInstruction => self.value().to_string(),
_ => String::new(),
}
}
fn to_xml(&self) -> String {
to_xml_int(self, &OutputDefinition::new(), vec![], 0)
}
fn to_xml_with_options(&self, od: &OutputDefinition) -> String {
to_xml_int(self, od, vec![], 0)
}
fn is_same(&self, other: &Self) -> bool {
Rc::ptr_eq(self, other)
}
fn document_order(&self) -> Vec<usize> {
doc_order(self)
}
fn cmp_document_order(&self, other: &Self) -> Ordering {
let this_order = self.document_order();
let other_order = other.document_order();
let mut this_it = this_order.iter();
let mut other_it = other_order.iter();
for _i in 0.. {
match (this_it.next(), other_it.next()) {
(Some(t), Some(o)) => {
if t < o {
return Ordering::Less;
} else if t > o {
return Ordering::Greater;
}
}
(Some(_), None) => return Ordering::Greater,
(None, Some(_)) => return Ordering::Less,
(None, None) => return Ordering::Equal,
}
}
Ordering::Equal
}
fn child_iter(&self) -> Self::NodeIterator {
Box::new(Children::new(self))
}
fn ancestor_iter(&self) -> Self::NodeIterator {
Box::new(Ancestors::new(self))
}
fn owner_document(&self) -> Self {
if self.node_type() == NodeType::Document {
self.clone()
} else {
self.ancestor_iter().last().unwrap()
}
}
fn descend_iter(&self) -> Self::NodeIterator {
Box::new(Descendants::new(self))
}
fn next_iter(&self) -> Self::NodeIterator {
Box::new(Siblings::new(self, 1))
}
fn prev_iter(&self) -> Self::NodeIterator {
Box::new(Siblings::new(self, -1))
}
fn attribute_iter(&self) -> Self::NodeIterator {
Box::new(Attributes::new(self))
}
fn get_attribute(&self, a: &QualifiedName) -> Rc<Value> {
self.attributes
.borrow()
.get(a)
.map_or(Rc::new(Value::from("")), |v| {
v.value.as_ref().unwrap().clone()
})
}
fn get_attribute_node(&self, a: &QualifiedName) -> Option<RNode> {
self.attributes
.borrow()
.get(a)
.map_or(None, |v| Some(v.clone()))
}
fn new_element(&self, qn: QualifiedName) -> Result<Self, Error> {
Ok(NodeBuilder::new(NodeType::Element).name(qn).build())
}
fn new_text(&self, v: Rc<Value>) -> Result<Self, Error> {
Ok(NodeBuilder::new(NodeType::Text).value(v).build())
}
fn new_attribute(&self, qn: QualifiedName, v: Rc<Value>) -> Result<Self, Error> {
Ok(NodeBuilder::new(NodeType::Attribute)
.name(qn)
.value(v)
.build())
}
fn new_comment(&self, v: Rc<Value>) -> Result<Self, Error> {
Ok(NodeBuilder::new(NodeType::Comment).value(v).build())
}
fn new_processing_instruction(&self, qn: QualifiedName, v: Rc<Value>) -> Result<Self, Error> {
Ok(NodeBuilder::new(NodeType::ProcessingInstruction)
.name(qn)
.value(v)
.build())
}
fn new_namespace(&self, _ns: String, _prefix: Option<String>) -> Result<Self, Error> {
Err(Error::new(ErrorKind::NotImplemented, "not supported"))
}
fn push(&mut self, n: RNode) -> Result<(), Error> {
if n.node_type() == NodeType::Document {
return Err(Error::new(
ErrorKind::TypeError,
String::from("document type nodes cannot be inserted into a tree"),
));
}
*n.parent.borrow_mut() = Some(Rc::downgrade(self));
self.children.borrow_mut().push(n);
Ok(())
}
fn pop(&mut self) -> Result<(), Error> {
let parent = self.parent().ok_or_else(|| {
Error::new(
ErrorKind::Unknown,
String::from("unable to insert before: node is an orphan"),
)
})?;
let idx = find_index(&parent, self)?;
parent.children.borrow_mut().remove(idx);
Ok(())
}
fn add_attribute(&self, att: Self) -> Result<(), Error> {
if self.node_type() != NodeType::Element {
return Result::Err(Error::new(
ErrorKind::Unknown,
String::from("must be an element node"),
));
}
if att.node_type() != NodeType::Attribute {
return Result::Err(Error::new(
ErrorKind::Unknown,
String::from("must be an attribute node"),
));
}
self.attributes.borrow_mut().insert(att.name(), att.clone());
*att.parent.borrow_mut() = Some(Rc::downgrade(self));
Ok(())
}
fn insert_before(&mut self, mut insert: Self) -> Result<(), Error> {
if insert.node_type() == NodeType::Document {
return Err(Error::new(
ErrorKind::TypeError,
String::from("document type nodes cannot be inserted into a tree"),
));
}
_ = insert.pop();
let parent = self.parent().ok_or_else(|| {
Error::new(
ErrorKind::Unknown,
String::from("unable to insert before: node is an orphan"),
)
})?;
let idx = find_index(&parent, self)?;
parent.children.borrow_mut().insert(idx, insert);
Ok(())
}
fn shallow_copy(&self) -> Result<Self, Error> {
Ok(NodeBuilder::new(self.node_type())
.name(self.name())
.value(self.value())
.build())
}
fn deep_copy(&self) -> Result<Self, Error> {
let mut result = NodeBuilder::new(self.node_type())
.name(self.name())
.value(self.value())
.build();
self.attribute_iter().try_for_each(|a| {
result.add_attribute(a.deep_copy()?)?;
Ok::<(), Error>(())
})?;
self.child_iter().try_for_each(|c| {
result.push(c.deep_copy()?)?;
Ok::<(), Error>(())
})?;
Ok(result)
}
fn get_canonical(&self) -> Result<Self, Error> {
match self.node_type() {
NodeType::Comment => Err(Error::new(ErrorKind::TypeError, "".to_string())),
NodeType::Text => {
let mut v: Rc<Value> = self.value();
if let Value::String(s) = &*v {
v = Rc::new(Value::String(s.replace("\r\n", "\n").replace("\n\n", "\n")))
}
let result = NodeBuilder::new(self.node_type())
.name(self.name())
.value(v)
.build();
Ok(result)
}
_ => {
let mut result = NodeBuilder::new(self.node_type())
.name(self.name())
.value(self.value())
.build();
self.attribute_iter().try_for_each(|a| {
result.add_attribute(a.deep_copy()?)?;
Ok::<(), Error>(())
})?;
self.child_iter().try_for_each(|c| {
result.push(c.get_canonical()?)?;
Ok::<(), Error>(())
})?;
Ok(result)
}
}
}
fn xmldecl(&self) -> crate::xmldecl::XMLDecl {
crate::xmldecl::XMLDeclBuilder::new().build()
}
fn set_xmldecl(&mut self, _: crate::xmldecl::XMLDecl) -> Result<(), Error> {
Err(Error::new(
ErrorKind::NotImplemented,
String::from("not implemented"),
))
}
fn add_namespace(&self, _ns: Self) -> Result<(), Error> {
todo!()
}
fn namespace_iter(&self) -> Self::NodeIterator {
todo!()
}
}
impl Debug for Node {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"type {} name {:?} value {:?}",
self.node_type, self.name, self.value
)
}
}
fn doc_order(n: &RNode) -> Vec<usize> {
match n.node_type {
NodeType::Document => vec![1 as usize],
NodeType::Element
| NodeType::Text
| NodeType::Comment
| NodeType::ProcessingInstruction => {
let p = n.parent.borrow();
match &*p {
Some(q) => match Weak::upgrade(&q) {
Some(r) => {
let idx = find_index(&r, &n).expect("unable to locate node in parent");
let mut a = doc_order(&r);
a.push(idx + 2);
a
}
None => vec![1 as usize],
},
None => vec![1 as usize],
}
}
NodeType::Attribute => {
let mut a = doc_order(&n.parent().unwrap());
a.push(2);
a
}
_ => vec![0],
}
}
fn to_xml_int(
node: &RNode,
od: &OutputDefinition,
ns: Vec<(String, Option<String>)>,
indent: usize,
) -> String {
match node.node_type {
NodeType::Document => node
.children
.borrow()
.iter()
.fold(String::new(), |mut result, c| {
result.push_str(to_xml_int(c, od, ns.clone(), indent + 2).as_str());
result
}),
NodeType::Element => {
let mut result = String::from("<");
let qn = node.name.borrow().as_ref().unwrap().clone();
result.push_str(qn.to_string().as_str());
let mut declared = ns.clone();
let mut newns: Vec<(String, Option<String>)> = vec![];
namespace_check(&qn, &declared).iter().for_each(|m| {
newns.push(m.clone());
declared.push(m.clone())
});
node.attributes.borrow().iter().for_each(|(k, _)| {
namespace_check(k, &declared).iter().for_each(|m| {
newns.push(m.clone());
declared.push(m.clone())
})
});
node.child_iter()
.filter(|c| c.node_type == NodeType::Element)
.for_each(|c| {
c.name.borrow().as_ref().map(|d| {
namespace_check(d, &declared).iter().for_each(|m| {
newns.push(m.clone());
declared.push(m.clone())
})
});
});
newns.iter().for_each(|(u, p)| {
result.push_str(" xmlns");
if let Some(q) = p {
result.push(':');
result.push_str(q.as_str());
}
result.push_str("='");
result.push_str(u);
result.push('\'');
});
node.attributes
.borrow()
.iter()
.for_each(|(k, v)| result.push_str(format!(" {}='{}'", k, v.value()).as_str()));
result.push('>');
let do_indent: bool = od
.get_indent()
.then(|| {
node.child_iter().fold(true, |mut acc, c| {
if acc && c.node_type == NodeType::Text {
acc = false
}
acc
})
})
.map_or(false, |b| b);
node.children.borrow().iter().for_each(|c| {
if do_indent {
result.push('\n');
(0..indent).for_each(|_| result.push(' '))
}
result.push_str(to_xml_int(c, od, newns.clone(), indent + 2).as_str())
});
if do_indent && indent > 1 {
result.push('\n');
(0..(indent - 2)).for_each(|_| result.push(' '))
}
result.push_str("</");
result.push_str(
node.name
.borrow()
.as_ref()
.map_or(String::new(), |n| n.to_string())
.as_str(),
);
result.push('>');
result
}
NodeType::Text => node.value().to_string(),
NodeType::Comment => {
let mut result = String::from("<!--");
let s = node
.value
.as_ref()
.map_or("".to_string(), |n| n.to_string());
result.push_str(s.as_str());
result.push_str("-->");
result
}
NodeType::ProcessingInstruction => {
let mut result = String::from("<?");
let s = node
.name
.borrow()
.as_ref()
.map_or("".to_string(), |n| n.to_string());
result.push_str(s.as_str());
result.push(' ');
let t = node.value.clone().map_or("".to_string(), |n| n.to_string());
result.push_str(t.as_str());
result.push_str("?>");
result
}
_ => String::new(),
}
}
fn namespace_check(
qn: &QualifiedName,
ns: &Vec<(String, Option<String>)>,
) -> Option<(String, Option<String>)> {
let mut result = None;
if let Some(qnuri) = qn.get_nsuri_ref() {
if ns.iter().find(|(u, _)| u == qnuri).is_some() {
} else {
result = Some((qnuri.to_string(), qn.get_prefix()))
}
}
result
}
fn find_index(p: &RNode, c: &RNode) -> Result<usize, Error> {
let idx = p
.children
.borrow()
.iter()
.enumerate()
.fold(None, |mut acc, (i, v)| {
if Rc::ptr_eq(c, v) {
acc = Some(i);
}
acc
});
idx.map_or(
Err(Error::new(
ErrorKind::Unknown,
String::from("unable to find child"),
)),
Ok,
)
}
pub struct Children {
v: Vec<RNode>,
i: usize,
}
impl Children {
fn new(n: &RNode) -> Self {
match n.node_type() {
NodeType::Document | NodeType::Element => Children {
v: n.children.borrow().clone(),
i: 0,
},
_ => Children { v: vec![], i: 0 },
}
}
}
impl Iterator for Children {
type Item = RNode;
fn next(&mut self) -> Option<RNode> {
match self.v.get(self.i) {
Some(c) => {
self.i += 1;
Some(c.clone())
}
None => None,
}
}
}
pub struct Ancestors {
cur: RNode,
}
impl Ancestors {
fn new(n: &RNode) -> Self {
Ancestors { cur: n.clone() }
}
}
impl Iterator for Ancestors {
type Item = RNode;
fn next(&mut self) -> Option<RNode> {
let s = self.cur.clone();
let p = s.parent.borrow();
match &*p {
None => None,
Some(q) => match Weak::upgrade(q) {
None => None,
Some(r) => {
self.cur = r.clone();
Some(r)
}
},
}
}
}
pub struct Descendants {
v: Vec<RNode>,
cur: usize,
}
impl Descendants {
fn new(n: &RNode) -> Self {
Descendants {
v: n.children.borrow().iter().fold(vec![], |mut acc, c| {
let mut d = descendant_add(c);
acc.append(&mut d);
acc
}),
cur: 0,
}
}
}
fn descendant_add(n: &RNode) -> Vec<RNode> {
let mut result = vec![n.clone()];
n.children.borrow().iter().for_each(|c| {
let mut l = descendant_add(c);
result.append(&mut l);
});
result
}
impl Iterator for Descendants {
type Item = RNode;
fn next(&mut self) -> Option<RNode> {
match self.v.get(self.cur) {
Some(n) => {
self.cur += 1;
Some(n.clone())
}
None => None,
}
}
}
pub struct Siblings(RNode, usize, i32);
impl Siblings {
fn new(n: &RNode, dir: i32) -> Self {
match n.parent() {
Some(p) => {
let (j, _) = p
.children
.borrow()
.iter()
.enumerate()
.find(|&(_, j)| Rc::ptr_eq(j, n))
.unwrap();
Siblings(p.clone(), j, dir)
}
None => {
Siblings(n.clone(), 0, -1)
}
}
}
}
impl Iterator for Siblings {
type Item = RNode;
fn next(&mut self) -> Option<RNode> {
if self.1 == 0 && self.2 < 0 {
None
} else {
let newidx = if self.2 < 0 {
self.1 - self.2.wrapping_abs() as usize
} else {
self.1 + self.2 as usize
};
match self.0.children.borrow().get(newidx) {
Some(n) => {
self.1 = newidx;
Some(n.clone())
}
None => None,
}
}
}
}
pub struct Attributes {
it: IntoIter<QualifiedName, RNode>,
}
impl Attributes {
fn new(n: &RNode) -> Self {
let b = n.attributes.borrow();
Attributes {
it: b.clone().into_iter(),
}
}
}
impl Iterator for Attributes {
type Item = RNode;
fn next(&mut self) -> Option<RNode> {
self.it.next().map(|(_, n)| n)
}
}
pub struct NodeBuilder(Node);
impl NodeBuilder {
pub fn new(n: NodeType) -> Self {
NodeBuilder(Node::new(n))
}
pub fn name(self, qn: QualifiedName) -> Self {
*self.0.name.borrow_mut() = Some(qn);
self
}
pub fn value(mut self, v: Rc<Value>) -> Self {
self.0.value = Some(v);
self
}
pub fn pi_name(mut self, pi: String) -> Self {
self.0.pi_name = Some(pi);
self
}
pub fn dtd(mut self, d: DTD) -> Self {
self.0.dtd = Some(d);
self
}
pub fn reference(mut self, qn: QualifiedName) -> Self {
self.0.reference = Some(qn);
self
}
pub fn build(self) -> Rc<Node> {
Rc::new(self.0)
}
}
#[derive(Clone, PartialEq)]
pub struct XMLDecl {
pub(crate) version: String,
pub(crate) encoding: Option<String>,
pub(crate) standalone: Option<String>,
}
impl XMLDecl {
pub fn new(version: String, encoding: Option<String>, standalone: Option<String>) -> Self {
XMLDecl {
version,
encoding,
standalone,
}
}
pub fn version(&self) -> String {
self.version.clone()
}
pub fn set_encoding(&mut self, e: String) {
self.encoding = Some(e)
}
pub fn encoding(&self) -> String {
self.encoding.as_ref().map_or(String::new(), |e| e.clone())
}
pub fn set_standalone(&mut self, s: String) {
self.standalone = Some(s)
}
pub fn standalone(&self) -> String {
self.standalone
.as_ref()
.map_or(String::new(), |e| e.clone())
}
}
impl fmt::Display for XMLDecl {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut result = String::from("<?xml version=\"");
result.push_str(self.version.as_str());
result.push('"');
if let Some(e) = self.encoding.as_ref() {
result.push_str(" encoding=\"");
result.push_str(e.as_str());
result.push('"');
};
if let Some(e) = self.standalone.as_ref() {
result.push_str(" standalone=\"");
result.push_str(e.as_str());
result.push('"');
};
f.write_str(result.as_str())
}
}
pub struct XMLDeclBuilder(XMLDecl);
impl Default for XMLDeclBuilder {
fn default() -> Self {
Self::new()
}
}
impl XMLDeclBuilder {
pub fn new() -> Self {
XMLDeclBuilder(XMLDecl {
version: String::new(),
encoding: None,
standalone: None,
})
}
pub fn version(mut self, v: String) -> Self {
self.0.version = v;
self
}
pub fn encoding(mut self, v: String) -> Self {
self.0.encoding = Some(v);
self
}
pub fn standalone(mut self, v: String) -> Self {
self.0.standalone = Some(v);
self
}
pub fn build(self) -> XMLDecl {
self.0
}
}
#[derive(Clone, PartialEq)]
pub struct DTD {
pub(crate) elements: HashMap<String, DTDDecl>,
pub(crate) attlists: HashMap<String, DTDDecl>,
pub(crate) notations: HashMap<String, DTDDecl>,
pub(crate) generalentities: HashMap<String, (String, bool)>, pub(crate) paramentities: HashMap<String, (String, bool)>,
publicid: Option<String>,
systemid: Option<String>,
name: Option<String>,
}
impl DTD {
pub fn new() -> DTD {
let default_entities = vec![
("amp".to_string(), ("&".to_string(), false)),
("gt".to_string(), (">".to_string(), false)),
("lt".to_string(), ("<".to_string(), false)),
("apos".to_string(), ("'".to_string(), false)),
("quot".to_string(), ("\"".to_string(), false)),
];
DTD {
elements: Default::default(),
attlists: Default::default(),
notations: Default::default(),
generalentities: default_entities.into_iter().collect(),
paramentities: HashMap::new(),
publicid: None,
systemid: None,
name: None,
}
}
}
impl Default for DTD {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DTDDecl {
Element(QualifiedName, String),
Attlist(QualifiedName, String),
Notation(QualifiedName, String),
GeneralEntity(QualifiedName, String),
ParamEntity(QualifiedName, String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_push() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Test")))
.build();
root.push(child).expect("unable to append child");
assert_eq!(root.to_xml(), "<Test></Test>")
}
#[test]
fn doc_order() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Test")))
.build();
root.push(child.clone()).expect("unable to append child");
assert_eq!(child.document_order(), vec![1, 2])
}
#[test]
fn cmp_doc_order_1() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let child1 = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Before")))
.build();
root.push(child1.clone()).expect("unable to append child");
let child2 = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("After")))
.build();
root.push(child2.clone()).expect("unable to append child");
assert_eq!(child1.cmp_document_order(&child2), Ordering::Less);
assert_eq!(child2.cmp_document_order(&child1), Ordering::Greater);
}
#[test]
fn cmp_doc_order_2() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let child1 = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Before")))
.build();
root.push(child1.clone()).expect("unable to append child");
let child2 = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("After")))
.build();
root.push(child2.clone()).expect("unable to append child");
assert_eq!(child1.cmp_document_order(&child1), Ordering::Equal)
}
#[test]
fn get_attr() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Test")))
.build();
root.push(child.clone()).expect("unable to append child");
let at = root
.new_attribute(
QualifiedName::new(None, None, String::from("mode")),
Rc::new(Value::from("testing")),
)
.expect("unable to create attribute node");
child.add_attribute(at).expect("unable to add attribute");
assert_eq!(
child.get_attribute(&QualifiedName::new(None, None, String::from("mode"))),
Value::from("testing").into()
)
}
#[test]
fn get_attr_neg() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Test")))
.build();
root.push(child.clone()).expect("unable to append child");
let at = root
.new_attribute(
QualifiedName::new(None, None, String::from("mode")),
Rc::new(Value::from("testing")),
)
.expect("unable to create attribute node");
child.add_attribute(at).expect("unable to add attribute");
assert_eq!(
child.get_attribute(&QualifiedName::new(None, None, String::from("foo"))),
Value::from("").into()
)
}
#[test]
fn child_iter() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let mut child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Test")))
.build();
root.push(child.clone()).expect("unable to append child");
(1..=5).for_each(|i| {
let mut l1 = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Level1")))
.build();
child.push(l1.clone()).expect("unable to append child");
l1.push(
NodeBuilder::new(NodeType::Text)
.value(Rc::new(Value::from(i)))
.build(),
)
.expect("unable to append child");
});
assert_eq!(root.to_xml(), "<Test><Level1>1</Level1><Level1>2</Level1><Level1>3</Level1><Level1>4</Level1><Level1>5</Level1></Test>")
}
#[test]
fn pop() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let mut child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Test")))
.build();
root.push(child.clone()).expect("unable to append child");
(1..=5).for_each(|i| {
let mut l1 = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Level1")))
.build();
child.push(l1.clone()).expect("unable to append child");
l1.push(
NodeBuilder::new(NodeType::Text)
.value(Rc::new(Value::from(i)))
.build(),
)
.expect("unable to append child");
});
child
.child_iter()
.nth(2)
.unwrap()
.pop()
.expect("unable to remove node");
assert_eq!(
root.to_xml(),
"<Test><Level1>1</Level1><Level1>2</Level1><Level1>4</Level1><Level1>5</Level1></Test>"
)
}
#[test]
fn deep_copy() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let mut child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(None, None, String::from("Test")))
.build();
root.push(child.clone()).expect("unable to append child");
child
.add_attribute(
NodeBuilder::new(NodeType::Attribute)
.name(QualifiedName::new(None, None, String::from("id")))
.value(Rc::new(Value::from("foo")))
.build(),
)
.expect("unable to add attribute");
child
.push(
NodeBuilder::new(NodeType::Text)
.value(Rc::new(Value::from("1234")))
.build(),
)
.expect("unable to add text node");
assert_eq!(
root.deep_copy().expect("unable to copy").to_xml(),
"<Test id='foo'>1234</Test>"
)
}
#[test]
fn to_xml() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let mut child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(
Some(String::from("http://test.org/")),
Some(String::from("eg")),
String::from("Test"),
))
.build();
root.push(child.clone()).expect("unable to append child");
child
.add_attribute(
NodeBuilder::new(NodeType::Attribute)
.name(QualifiedName::new(None, None, String::from("id")))
.value(Rc::new(Value::from("foo")))
.build(),
)
.expect("unable to add attribute");
child
.push(
NodeBuilder::new(NodeType::Text)
.value(Rc::new(Value::from("1234")))
.build(),
)
.expect("unable to add text node");
assert_eq!(
root.to_xml(),
"<eg:Test xmlns:eg='http://test.org/' id='foo'>1234</eg:Test>"
)
}
#[test]
fn to_xml_with_options() {
let mut root = NodeBuilder::new(NodeType::Document).build();
let mut child = NodeBuilder::new(NodeType::Element)
.name(QualifiedName::new(
Some(String::from("http://test.org/")),
Some(String::from("eg")),
String::from("Test"),
))
.build();
root.push(child.clone()).expect("unable to append child");
child
.add_attribute(
NodeBuilder::new(NodeType::Attribute)
.name(QualifiedName::new(None, None, String::from("id")))
.value(Rc::new(Value::from("foo")))
.build(),
)
.expect("unable to add attribute");
let mut l1 = root
.new_element(QualifiedName::new(
Some(String::from("http://test.org/")),
Some(String::from("eg")),
String::from("Level-1"),
))
.expect("unable to create element");
child.push(l1.clone()).expect("unable to add node");
l1.push(
NodeBuilder::new(NodeType::Text)
.value(Rc::new(Value::from("1234")))
.build(),
)
.expect("unable to add text node");
let mut od = OutputDefinition::new();
od.set_indent(true);
assert_eq!(
root.to_xml_with_options(&od),
r#"<eg:Test xmlns:eg='http://test.org/' id='foo'>
<eg:Level-1>1234</eg:Level-1>
</eg:Test>"#
)
}
}