FIX: think of a better place to put this, and maybe a better interface
(context: &Context<'c>, var_name: &str, mathml: Element<'c>)
| 263 | |
| 264 | // FIX: think of a better place to put this, and maybe a better interface |
| 265 | pub fn context_get_variable<'c>(context: &Context<'c>, var_name: &str, mathml: Element<'c>) -> Result<(Option<String>, Option<f64>)> { |
| 266 | // First return tuple value is string-value (if string, bool, or single node) or None |
| 267 | // Second return tuple value is f64 if variable is a number or None |
| 268 | // This is ridiculously complicated for what in the end is a hashmap lookup |
| 269 | // There isn't an API that lets us get at the value, so we have to setup/build/evaluate an xpath |
| 270 | // Note: mathml can be any node. It isn't really used but some Element needs to be part of Evaluate() |
| 271 | let factory = Factory::new(); |
| 272 | match factory.build(&("$".to_string() + var_name)) { |
| 273 | Err(_) => bail!("Could not compile XPath for variable: {}", var_name), |
| 274 | Ok(xpath) => match xpath.unwrap().evaluate(context, mathml) { |
| 275 | Ok(val) => return Ok( match val { |
| 276 | Value::String(s) => (Some(s), None), |
| 277 | Value::Number(f) => (None, Some(f)), |
| 278 | Value::Boolean(b) => (Some(format!("{}", b)), None), |
| 279 | Value::Nodeset(nodes) => { |
| 280 | if nodes.size() == 1 { |
| 281 | if let Some(attr) = nodes.document_order_first().unwrap().attribute() { |
| 282 | return Ok( (Some(attr.value().to_string()), None) ); |
| 283 | } |
| 284 | }; |
| 285 | let mut error_message = format!("Variable '{}' set somewhere in navigate.yaml is nodeset and not an attribute: ", var_name); |
| 286 | if nodes.size() == 0 { |
| 287 | error_message += &format!("0 nodes (false) -- {} set to non-existent (following?/preceding?) node", var_name); |
| 288 | } else { |
| 289 | let singular = nodes.size()==1; |
| 290 | error_message += &format!("{} node{}. {}:", |
| 291 | nodes.size(), |
| 292 | if singular {""} else {"s"}, |
| 293 | if singular {"Node is"} else {"Nodes are"}); |
| 294 | nodes.document_order() |
| 295 | .iter() |
| 296 | .enumerate() |
| 297 | .for_each(|(i, node)| { |
| 298 | match node { |
| 299 | sxd_xpath::nodeset::Node::Element(mathml) => |
| 300 | error_message += &format!("#{}:\n{}",i, mml_to_string(mathml)), |
| 301 | _ => error_message += &format!("'{:?}'", node), |
| 302 | } |
| 303 | }) |
| 304 | }; |
| 305 | bail!(error_message); |
| 306 | }, |
| 307 | } ), |
| 308 | Err(_) => bail!("Could not find value for navigation variable '{}'", var_name), |
| 309 | } |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | /// Given a key code along with the modifier keys, the current node is moved accordingly (or value reported in some cases).] |
| 314 | /// The spoken text for the new current node is returned. |
no test coverage detected