use bindings::*;
use c_helpers::*;
use libc;
use libc::{c_char, c_void, size_t};
use std::ffi::{CStr, CString};
use std::str;
use tree::{Document, DocumentRef, Node};
#[derive(Clone)]
pub struct Context {
pub context_ptr: xmlXPathContextPtr,
document: DocumentRef,
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
xmlXPathFreeContext(self.context_ptr);
}
}
}
#[derive(Clone)]
pub struct Object {
pub ptr: xmlXPathObjectPtr,
document: DocumentRef,
}
impl Context {
pub fn new(doc: &Document) -> Result<Context, ()> {
let ctxtptr = unsafe { xmlXPathNewContext(doc.doc_ptr()) };
if ctxtptr.is_null() {
Err(())
} else {
Ok(Context {
context_ptr: ctxtptr,
document: doc.0.clone(),
})
}
}
pub(crate) fn new_ptr(docref: DocumentRef) -> Result<Context, ()> {
let ctxtptr = unsafe { xmlXPathNewContext(docref.borrow().doc_ptr) };
if ctxtptr.is_null() {
Err(())
} else {
Ok(Context {
context_ptr: ctxtptr,
document: docref.clone(),
})
}
}
pub fn register_namespace(&self, prefix: &str, href: &str) -> Result<(), ()> {
let c_prefix = CString::new(prefix).unwrap();
let c_href = CString::new(href).unwrap();
unsafe {
let result = xmlXPathRegisterNs(
self.context_ptr,
c_prefix.as_bytes().as_ptr(),
c_href.as_bytes().as_ptr(),
);
if result != 0 {
Err(())
} else {
Ok(())
}
}
}
pub fn evaluate(&self, xpath: &str) -> Result<Object, ()> {
let c_xpath = CString::new(xpath).unwrap();
let ptr = unsafe { xmlXPathEvalExpression(c_xpath.as_bytes().as_ptr(), self.context_ptr) };
if ptr.is_null() {
Err(())
} else {
Ok(Object {
ptr,
document: self.document.clone(),
})
}
}
pub fn set_context_node(&mut self, node: &Node) -> Result<(), ()> {
unsafe {
let result = xmlXPathSetContextNode(node.node_ptr(), self.context_ptr);
if result != 0 {
return Err(());
}
}
Ok(())
}
pub fn findnodes(&mut self, xpath: &str, node_opt: Option<&Node>) -> Result<Vec<Node>, ()> {
if let Some(node) = node_opt {
self.set_context_node(node)?;
}
let evaluated = self.evaluate(xpath)?;
Ok(evaluated.get_nodes_as_vec())
}
pub fn findvalue(&mut self, xpath: &str, node_opt: Option<&Node>) -> Result<String, ()> {
if let Some(node) = node_opt {
self.set_context_node(node)?;
}
let evaluated = self.evaluate(xpath)?;
Ok(evaluated.to_string())
}
}
impl Drop for Object {
fn drop(&mut self) {
unsafe {
xmlXPathFreeObject(self.ptr);
}
}
}
impl Object {
pub fn get_number_of_nodes(&self) -> usize {
let v = xmlXPathObjectNumberOfNodes(self.ptr);
if v == -1 {
panic!("rust-libxml: xpath: Passed in null pointer!");
}
if v == -2 {
return 0;
}
if v < -2 {
panic!("rust-libxml: xpath: expected non-negative number of result nodes");
}
v as usize
}
pub fn get_nodes_as_vec(&self) -> Vec<Node> {
let n = self.get_number_of_nodes();
let mut vec: Vec<Node> = Vec::with_capacity(n);
for i in 0..n {
let ptr = xmlXPathObjectGetNode(self.ptr, i as size_t);
if ptr.is_null() {
panic!("rust-libxml: xpath: found null pointer result set");
}
let node = Node::wrap(ptr, self.document.clone());
vec.push(node);
}
vec
}
pub fn to_string(&self) -> String {
unsafe {
let receiver = xmlXPathCastToString(self.ptr);
let c_string = CStr::from_ptr(receiver as *const c_char);
let rust_string = str::from_utf8(c_string.to_bytes()).unwrap().to_owned();
libc::free(receiver as *mut c_void);
rust_string
}
}
}