use crate::arena::NodeId;
use crate::document::Document;
use crate::error::{Result, XmlError};
use crate::node::NodeKind;
fn parse_bool(s: &str) -> Result<bool> {
let s_trimmed = s.trim();
if s_trimmed.eq_ignore_ascii_case("true") || s_trimmed == "1" {
Ok(true)
} else if s_trimmed.eq_ignore_ascii_case("false") || s_trimmed == "0" {
Ok(false)
} else {
Err(XmlError::WrongAttributeType)
}
}
fn parse_numeric<T: std::str::FromStr>(s: &str) -> Result<T> {
s.trim()
.parse::<T>()
.map_err(|_| XmlError::WrongAttributeType)
}
fn parse_bool_text(s: &str) -> Result<bool> {
let s_trimmed = s.trim();
if s_trimmed.eq_ignore_ascii_case("true") || s_trimmed == "1" {
Ok(true)
} else if s_trimmed.eq_ignore_ascii_case("false") || s_trimmed == "0" {
Ok(false)
} else {
Err(XmlError::CanNotConvertText)
}
}
fn parse_numeric_text<T: std::str::FromStr>(s: &str) -> Result<T> {
s.trim()
.parse::<T>()
.map_err(|_| XmlError::CanNotConvertText)
}
impl Document {
pub fn query_int_attribute(&self, el: NodeId, name: &str) -> Result<i32> {
let val = self.attribute(el, name).ok_or(XmlError::NoAttribute)?;
parse_numeric(val)
}
pub fn query_unsigned_attribute(&self, el: NodeId, name: &str) -> Result<u32> {
let val = self.attribute(el, name).ok_or(XmlError::NoAttribute)?;
parse_numeric(val)
}
pub fn query_int64_attribute(&self, el: NodeId, name: &str) -> Result<i64> {
let val = self.attribute(el, name).ok_or(XmlError::NoAttribute)?;
parse_numeric(val)
}
pub fn query_bool_attribute(&self, el: NodeId, name: &str) -> Result<bool> {
let val = self.attribute(el, name).ok_or(XmlError::NoAttribute)?;
parse_bool(val)
}
pub fn query_double_attribute(&self, el: NodeId, name: &str) -> Result<f64> {
let val = self.attribute(el, name).ok_or(XmlError::NoAttribute)?;
parse_numeric(val)
}
pub fn query_float_attribute(&self, el: NodeId, name: &str) -> Result<f32> {
let val = self.attribute(el, name).ok_or(XmlError::NoAttribute)?;
parse_numeric(val)
}
#[must_use]
pub fn int_attribute(&self, el: NodeId, name: &str, default: i32) -> i32 {
self.query_int_attribute(el, name).unwrap_or(default)
}
#[must_use]
pub fn bool_attribute(&self, el: NodeId, name: &str, default: bool) -> bool {
self.query_bool_attribute(el, name).unwrap_or(default)
}
#[must_use]
pub fn double_attribute(&self, el: NodeId, name: &str, default: f64) -> f64 {
self.query_double_attribute(el, name).unwrap_or(default)
}
#[must_use]
pub fn float_attribute(&self, el: NodeId, name: &str, default: f32) -> f32 {
self.query_float_attribute(el, name).unwrap_or(default)
}
#[must_use]
pub fn get_text(&self, el: NodeId) -> Option<&str> {
let mut child = self.first_child(el);
while let Some(c) = child {
if let Some(data) = self.arena.get(c) {
if let NodeKind::Text(txt_data) = &data.kind {
return Some(txt_data.content.as_str());
}
}
child = self.next_sibling(c);
}
None
}
pub fn set_text(&mut self, el: NodeId, text: &str) -> Result<()> {
let mut child = self.first_child(el);
let mut text_node_id = None;
while let Some(c) = child {
if let Some(data) = self.arena.get(c) {
if let NodeKind::Text(_) = &data.kind {
text_node_id = Some(c);
break;
}
}
child = self.next_sibling(c);
}
if let Some(tid) = text_node_id {
let data = self.arena.get_mut(tid).ok_or(XmlError::InvalidNodeId)?;
if let NodeKind::Text(txt_data) = &mut data.kind {
txt_data.content = text.to_string();
}
} else {
let new_txt = self.new_text(text);
self.insert_first_child(el, new_txt)?;
}
Ok(())
}
pub fn query_int_text(&self, el: NodeId) -> Result<i32> {
let val = self.get_text(el).ok_or(XmlError::NoTextNode)?;
parse_numeric_text(val)
}
pub fn query_bool_text(&self, el: NodeId) -> Result<bool> {
let val = self.get_text(el).ok_or(XmlError::NoTextNode)?;
parse_bool_text(val)
}
pub fn query_double_text(&self, el: NodeId) -> Result<f64> {
let val = self.get_text(el).ok_or(XmlError::NoTextNode)?;
parse_numeric_text(val)
}
#[must_use]
pub fn int_text(&self, el: NodeId, default: i32) -> i32 {
self.query_int_text(el).unwrap_or(default)
}
#[must_use]
pub fn bool_text(&self, el: NodeId, default: bool) -> bool {
self.query_bool_text(el).unwrap_or(default)
}
}