use std::io;
use html5ever::serialize;
use string_cache::{Atom, Namespace, QualName};
use tendril::StrTendril;
use document::Document;
use predicate::Predicate;
use selection::Selection;
#[derive(Clone, Debug, PartialEq)]
pub enum Data {
Text(StrTendril),
Element(Atom, Vec<(Atom, StrTendril)>, Vec<usize>),
Comment(StrTendril)
}
#[derive(Clone, Debug, PartialEq)]
pub struct Raw {
pub index: usize,
pub parent: Option<usize>,
pub prev: Option<usize>,
pub next: Option<usize>,
pub data: Data
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Node<'a> {
document: &'a Document,
index: usize
}
impl<'a> Node<'a> {
pub fn new(document: &'a Document, index: usize) -> Node<'a> {
Node {
document: document,
index: index
}
}
pub fn index(&self) -> usize {
self.index
}
pub fn raw(&self) -> &Raw {
&self.document.nodes[self.index]
}
pub fn data(&self) -> &Data {
&self.raw().data
}
pub fn name(&self) -> Option<&str> {
match *self.data() {
Data::Element(ref name, _, _) => Some(name),
_ => None
}
}
pub fn attr(&self, name: &str) -> Option<&str> {
match *self.data() {
Data::Element(_, ref attrs, _) => {
let name = Atom::from(name);
attrs.iter()
.find(|&&(ref name_, _)| name == *name_)
.map(|&(_, ref value)| value.as_ref())
},
_ => None
}
}
pub fn parent(&self) -> Option<Node<'a>> {
self.raw().parent.map(|index| self.document.nth(index))
}
pub fn prev(&self) -> Option<Node<'a>> {
self.raw().prev.map(|index| self.document.nth(index))
}
pub fn next(&self) -> Option<Node<'a>> {
self.raw().next.map(|index| self.document.nth(index))
}
pub fn text(&self) -> String {
let mut string = String::new();
recur(&self.document, self.index, &mut string);
return string;
fn recur(document: &Document, index: usize, string: &mut String) {
match document.nodes[index].data {
Data::Text(ref text) => string.push_str(text),
Data::Element(_, _, ref children) => {
for &child in children {
recur(document, child, string)
}
},
Data::Comment(_) => {}
}
}
}
pub fn html(&self) -> String {
let mut buf = Vec::new();
serialize::serialize(&mut buf, self, Default::default()).unwrap();
String::from_utf8(buf).unwrap()
}
pub fn inner_html(&self) -> String {
let mut buf = Vec::new();
if let Data::Element(_, _, ref children) = *self.data() {
for &child in children {
serialize::serialize(&mut buf,
&self.document.nth(child),
Default::default()).unwrap();
}
}
String::from_utf8(buf).unwrap()
}
pub fn find<P: Predicate>(&self, p: P) -> Selection<'a> {
Selection::new(self.document, [self.index].iter().cloned().collect()).find(p)
}
pub fn is<P: Predicate>(&self, p: P) -> bool {
p.matches(self)
}
pub fn as_text(&self) -> Option<&str> {
match *self.data() {
Data::Text(ref text) => Some(&text),
_ => None
}
}
pub fn as_comment(&self) -> Option<&str> {
match *self.data() {
Data::Comment(ref comment) => Some(&comment),
_ => None
}
}
pub fn children(&self) -> Selection<'a> {
Selection::new(self.document, match *self.data() {
Data::Element(_, _, ref children) => children.iter().cloned().collect(),
_ => [].iter().cloned().collect()
})
}
}
impl<'a> serialize::Serializable for Node<'a> {
fn serialize<'w, W: io::Write>(&self,
serializer: &mut serialize::Serializer<'w, W>,
traversal_scope: serialize::TraversalScope)
-> io::Result<()> {
match *self.data() {
Data::Text(ref text) => serializer.write_text(&text),
Data::Element(ref name, ref attrs, ref children) => {
let ns = Namespace("".into());
let name = QualName::new(ns.clone(), name.clone());
let attrs = attrs.iter().map(|&(ref name, ref value)| {
(QualName::new(ns.clone(), name.clone()), value.as_ref())
}).collect::<Vec<(QualName, &str)>>();
let attrs = attrs.iter().map(|&(ref name, ref value)| {
(name, *value)
});
try!(serializer.start_elem(name.clone(), attrs));
for &child in children {
let child = self.document.nth(child);
try!(serialize::Serializable::serialize(&child,
serializer,
traversal_scope));
}
try!(serializer.end_elem(name.clone()));
Ok(())
},
Data::Comment(ref comment) => serializer.write_comment(&comment)
}
}
}