sup_xml_core/xpath/exslt/
mod.rs1use crate::error::XmlError;
22use crate::xpath::eval::{Numeric, Value};
23use crate::xpath::index::DocIndexLike;
24
25pub mod math;
26pub mod date;
27pub mod str;
28pub mod sets;
29pub mod regexp;
30pub mod common;
31
32type Result<T> = std::result::Result<T, XmlError>;
33
34pub const MATH_NS: &str = "http://exslt.org/math";
37pub const DATE_NS: &str = "http://exslt.org/dates-and-times";
38pub const STR_NS: &str = "http://exslt.org/strings";
39pub const SET_NS: &str = "http://exslt.org/sets";
40pub const REGEXP_NS: &str = "http://exslt.org/regular-expressions";
41pub const COMMON_NS: &str = "http://exslt.org/common";
42pub const DYN_NS: &str = "http://exslt.org/dynamic";
43pub const XPATH_MATH_NS: &str = "http://www.w3.org/2005/xpath-functions/math";
47
48pub fn dispatch<I: DocIndexLike>(
58 ns_uri: &str,
59 name: &str,
60 args: Vec<Value>,
61 idx: &I,
62) -> Option<Result<Value>> {
63 match ns_uri {
64 MATH_NS => math::dispatch(name, args, idx),
65 DATE_NS => date::dispatch(name, args, idx),
66 STR_NS => self::str::dispatch(name, args, idx),
67 SET_NS => sets::dispatch(name, args, idx),
68 REGEXP_NS => regexp::dispatch(name, args, idx),
69 COMMON_NS => common::dispatch(name, args, idx),
70 XPATH_MATH_NS => xpath_math_dispatch(name, args, idx),
71 _ => None,
76 }
77}
78
79fn xpath_math_dispatch<I: DocIndexLike>(
85 name: &str, args: Vec<Value>, idx: &I,
86) -> Option<Result<Value>> {
87 use crate::error::{ErrorDomain, ErrorLevel};
88 let err = |msg: &str| XmlError::new(ErrorDomain::XPath, ErrorLevel::Error, msg.to_string());
89 fn num<I: DocIndexLike>(v: &Value, idx: &I) -> f64 {
90 crate::xpath::eval::value_to_number(v, idx)
91 }
92 let r = match name {
93 "pi" => {
94 if !args.is_empty() { return Some(Err(err("math:pi() takes no arguments"))); }
95 Ok(Value::Number(Numeric::Double(std::f64::consts::PI)))
96 }
97 "exp" | "exp10" | "log" | "log10"
98 | "sqrt" | "sin" | "cos" | "tan"
99 | "asin" | "acos" | "atan" => {
100 if args.len() != 1 {
101 return Some(Err(err(
102 &format!("math:{name}() takes 1 argument"))));
103 }
104 let n = num(&args[0], idx);
105 let r = match name {
106 "exp" => n.exp(),
107 "exp10" => 10_f64.powf(n),
108 "log" => n.ln(),
109 "log10" => n.log10(),
110 "sqrt" => n.sqrt(),
111 "sin" => n.sin(),
112 "cos" => n.cos(),
113 "tan" => n.tan(),
114 "asin" => n.asin(),
115 "acos" => n.acos(),
116 "atan" => n.atan(),
117 _ => unreachable!(),
118 };
119 Ok(Value::Number(Numeric::Double(r)))
120 }
121 "pow" => {
122 if args.len() != 2 {
123 return Some(Err(err("math:pow() takes 2 arguments")));
124 }
125 let x = num(&args[0], idx);
126 let y = num(&args[1], idx);
127 Ok(Value::Number(Numeric::Double(x.powf(y))))
128 }
129 "atan2" => {
130 if args.len() != 2 {
131 return Some(Err(err("math:atan2() takes 2 arguments")));
132 }
133 let y = num(&args[0], idx);
134 let x = num(&args[1], idx);
135 Ok(Value::Number(Numeric::Double(y.atan2(x))))
136 }
137 _ => return None,
138 };
139 Some(r)
140}