pub(crate) mod booleans;
pub mod callable;
pub(crate) mod construct;
pub mod context;
pub(crate) mod controlflow;
pub(crate) mod datetime;
pub(crate) mod functions;
pub(crate) mod grouping;
mod keys;
pub(crate) mod logic;
pub(crate) mod misc;
pub(crate) mod navigate;
pub mod numbers;
pub(crate) mod strings;
pub mod template;
pub(crate) mod variables;
#[allow(unused_imports)]
use crate::item::Sequence;
use crate::item::{Item, Node, NodeType, SequenceTrait};
use crate::output::OutputSpec;
use crate::pattern::Pattern;
use crate::transform::callable::ActualParameters;
use crate::transform::context::{Context, ContextBuilder, StaticContext};
use crate::transform::numbers::Numbering;
use crate::value::Operator;
#[allow(unused_imports)]
use crate::value::Value;
use crate::xdmerror::{Error, ErrorKind};
use qualname::{NamespaceDeclaration, NamespaceMap, NamespacePrefix, NamespaceUri, NcName, QName};
use std::convert::TryFrom;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use url::Url;
#[derive(Clone)]
pub enum Transform<N: Node> {
Root,
ContextItem,
CurrentItem,
Compose(Vec<Transform<N>>),
Step(NodeMatch),
Filter(Box<Transform<N>>),
Empty,
Literal(Item<N>),
LiteralElement(QName, Box<Transform<N>>),
Element(Box<Transform<N>>, Box<Transform<N>>),
LiteralText(Box<Transform<N>>, OutputSpec),
LiteralAttribute(QName, Box<Transform<N>>),
LiteralComment(Box<Transform<N>>),
LiteralProcessingInstruction(Box<Transform<N>>, Box<Transform<N>>),
NamespaceDeclaration(
Option<Box<Transform<N>>>,
Box<Transform<N>>,
Box<Transform<N>>,
),
SequenceItems(Vec<Transform<N>>),
Copy(Box<Transform<N>>, Box<Transform<N>>),
DeepCopy(Box<Transform<N>>),
Or(Vec<Transform<N>>),
And(Vec<Transform<N>>),
GeneralComparison(Operator, Box<Transform<N>>, Box<Transform<N>>),
ValueComparison(Operator, Box<Transform<N>>, Box<Transform<N>>),
Concat(Vec<Transform<N>>),
Range(Box<Transform<N>>, Box<Transform<N>>),
Arithmetic(Vec<ArithmeticOperand<N>>),
Loop(Vec<(String, Transform<N>)>, Box<Transform<N>>),
Switch(Vec<(Transform<N>, Transform<N>)>, Box<Transform<N>>),
ForEach(
Option<Grouping<N>>,
Box<Transform<N>>,
Box<Transform<N>>,
Vec<(Order, Transform<N>)>,
),
ApplyTemplates(Box<Transform<N>>, Option<QName>, Vec<(Order, Transform<N>)>),
ApplyImports,
NextMatch,
Union(Vec<Transform<N>>),
Call(Box<Transform<N>>, Vec<Transform<N>>, Rc<NamespaceMap>),
VariableDeclaration(
String,
Box<Transform<N>>,
Box<Transform<N>>,
Rc<NamespaceMap>,
),
VariableReference(String, Rc<NamespaceMap>),
SetAttribute(QName, Box<Transform<N>>),
Position,
Last,
Count(Box<Transform<N>>),
LocalName(Option<Box<Transform<N>>>),
Name(Option<Box<Transform<N>>>),
String(Box<Transform<N>>),
StartsWith(Box<Transform<N>>, Box<Transform<N>>),
EndsWith(Box<Transform<N>>, Box<Transform<N>>),
Contains(Box<Transform<N>>, Box<Transform<N>>),
Substring(
Box<Transform<N>>,
Box<Transform<N>>,
Option<Box<Transform<N>>>,
),
SubstringBefore(Box<Transform<N>>, Box<Transform<N>>),
SubstringAfter(Box<Transform<N>>, Box<Transform<N>>),
NormalizeSpace(Option<Box<Transform<N>>>),
Translate(Box<Transform<N>>, Box<Transform<N>>, Box<Transform<N>>),
GenerateId(Option<Box<Transform<N>>>),
Boolean(Box<Transform<N>>),
Not(Box<Transform<N>>),
True,
False,
Number(Box<Transform<N>>),
Sum(Box<Transform<N>>),
Avg(Box<Transform<N>>),
Min(Box<Transform<N>>),
Max(Box<Transform<N>>),
Floor(Box<Transform<N>>),
Ceiling(Box<Transform<N>>),
Round(Box<Transform<N>>, Option<Box<Transform<N>>>),
CurrentDateTime,
CurrentDate,
CurrentTime,
FormatDateTime(
Box<Transform<N>>,
Box<Transform<N>>,
Option<Box<Transform<N>>>,
Option<Box<Transform<N>>>,
Option<Box<Transform<N>>>,
),
FormatDate(
Box<Transform<N>>,
Box<Transform<N>>,
Option<Box<Transform<N>>>,
Option<Box<Transform<N>>>,
Option<Box<Transform<N>>>,
),
FormatTime(
Box<Transform<N>>,
Box<Transform<N>>,
Option<Box<Transform<N>>>,
Option<Box<Transform<N>>>,
Option<Box<Transform<N>>>,
),
FormatNumber(
Box<Transform<N>>,
Box<Transform<N>>,
Option<Box<Transform<N>>>,
),
FormatInteger(Box<Transform<N>>, Box<Transform<N>>),
GenerateIntegers(Box<Transform<N>>, Box<Transform<N>>, Box<Numbering<N>>),
CurrentGroup,
CurrentGroupingKey,
Key(
Box<Transform<N>>,
Box<Transform<N>>,
Option<Box<Transform<N>>>,
Rc<NamespaceMap>,
),
SystemProperty(Box<Transform<N>>, Rc<NamespaceMap>),
AvailableSystemProperties,
Document(Box<Transform<N>>, Option<Box<Transform<N>>>),
Invoke(QName, ActualParameters<N>, Rc<NamespaceMap>),
Message(
Box<Transform<N>>,
Option<Box<Transform<N>>>,
Box<Transform<N>>,
Box<Transform<N>>,
),
NotImplemented(String),
Error(ErrorKind, String),
}
impl<N: Node> Debug for Transform<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Transform::Root => write!(f, "root node"),
Transform::ContextItem => write!(f, "context item"),
Transform::CurrentItem => write!(f, "current item"),
Transform::SequenceItems(v) => write!(f, "Sequence of {} items", v.len()),
Transform::Compose(v) => {
write!(f, "Compose {} steps [", v.len()).expect("unable to format step");
v.iter().for_each(|s| {
s.fmt(f).expect("unable to format step");
write!(f, "; ").expect("unable to format step")
});
write!(f, "]")
}
Transform::Step(nm) => write!(f, "Step matching {}", nm),
Transform::Filter(_) => write!(f, "Filter"),
Transform::Empty => write!(f, "Empty"),
Transform::Literal(_) => write!(f, "literal value"),
Transform::LiteralElement(qn, _) => write!(f, "literal element named \"{}\"", qn),
Transform::Element(_, _) => write!(f, "constructed element"),
Transform::LiteralText(_, b) => write!(f, "literal text (disable escaping {:?})", b),
Transform::LiteralAttribute(qn, _) => write!(f, "literal attribute named \"{}\"", qn),
Transform::LiteralComment(_) => write!(f, "literal comment"),
Transform::LiteralProcessingInstruction(_, _) => {
write!(f, "literal processing-instruction")
}
Transform::NamespaceDeclaration(_, _, _) => write!(f, "namespace declaration"),
Transform::Copy(_, _) => write!(f, "shallow copy"),
Transform::DeepCopy(_) => write!(f, "deep copy"),
Transform::GeneralComparison(o, v, u) => {
write!(f, "general comparison {} of {:?} and {:?}", o, v, u)
}
Transform::ValueComparison(o, v, u) => {
write!(f, "value comparison {} of {:?} and {:?}", o, v, u)
}
Transform::Concat(o) => write!(f, "Concatenate {} operands", o.len()),
Transform::Range(_, _) => write!(f, "range"),
Transform::Arithmetic(o) => write!(f, "Arithmetic {} operands", o.len()),
Transform::And(o) => write!(f, "AND {} operands", o.len()),
Transform::Or(o) => write!(f, "OR {} operands", o.len()),
Transform::Loop(_, _) => write!(f, "loop"),
Transform::Switch(c, _) => write!(f, "switch {} clauses", c.len()),
Transform::ForEach(_g, _, _, o) => write!(f, "for-each ({} sort keys)", o.len()),
Transform::Union(v) => {
write!(f, "union of {} operands", v.len()).ok();
v.iter().for_each(|o| {
write!(f, "\noperand: {:?}", o).ok();
});
Ok(())
}
Transform::ApplyTemplates(_, m, o) => {
write!(f, "Apply templates (mode {:?}, {} sort keys)", m, o.len())
}
Transform::Call(_, a, _) => write!(f, "Call transform with {} arguments", a.len()),
Transform::ApplyImports => write!(f, "Apply imports"),
Transform::NextMatch => write!(f, "next-match"),
Transform::VariableDeclaration(n, _, _, _) => write!(f, "declare variable \"{}\"", n),
Transform::VariableReference(n, _) => write!(f, "reference variable \"{}\"", n),
Transform::SetAttribute(n, _) => write!(f, "set attribute named \"{}\"", n),
Transform::Position => write!(f, "position"),
Transform::Last => write!(f, "last"),
Transform::Count(_s) => write!(f, "count()"),
Transform::Name(_n) => write!(f, "name()"),
Transform::LocalName(_n) => write!(f, "local-name()"),
Transform::String(s) => write!(f, "string({:?})", s),
Transform::StartsWith(s, t) => write!(f, "starts-with({:?}, {:?})", s, t),
Transform::EndsWith(s, t) => write!(f, "ends-with({:?}, {:?})", s, t),
Transform::Contains(s, t) => write!(f, "contains({:?}, {:?})", s, t),
Transform::Substring(s, t, _l) => write!(f, "substring({:?}, {:?}, ...)", s, t),
Transform::SubstringBefore(s, t) => write!(f, "substring-before({:?}, {:?})", s, t),
Transform::SubstringAfter(s, t) => write!(f, "substring-after({:?}, {:?})", s, t),
Transform::NormalizeSpace(_s) => write!(f, "normalize-space()"),
Transform::Translate(s, t, u) => write!(f, "translate({:?}, {:?}, {:?})", s, t, u),
Transform::GenerateId(_) => write!(f, "generate-id()"),
Transform::Boolean(b) => write!(f, "boolean({:?})", b),
Transform::Not(b) => write!(f, "not({:?})", b),
Transform::True => write!(f, "true"),
Transform::False => write!(f, "false"),
Transform::Number(n) => write!(f, "number({:?})", n),
Transform::Sum(n) => write!(f, "sum({:?})", n),
Transform::Avg(n) => write!(f, "avg({:?})", n),
Transform::Min(n) => write!(f, "min({:?})", n),
Transform::Max(n) => write!(f, "max({:?})", n),
Transform::Floor(n) => write!(f, "floor({:?})", n),
Transform::Ceiling(n) => write!(f, "ceiling({:?})", n),
Transform::Round(n, _p) => write!(f, "round({:?},...)", n),
Transform::CurrentDateTime => write!(f, "current-date-time"),
Transform::CurrentDate => write!(f, "current-date"),
Transform::CurrentTime => write!(f, "current-time"),
Transform::FormatDateTime(p, q, _, _, _) => {
write!(f, "format-date-time({:?}, {:?}, ...)", p, q)
}
Transform::FormatDate(p, q, _, _, _) => write!(f, "format-date({:?}, {:?}, ...)", p, q),
Transform::FormatTime(p, q, _, _, _) => write!(f, "format-time({:?}, {:?}, ...)", p, q),
Transform::FormatNumber(v, p, _) => write!(f, "format-number({:?}, {:?})", v, p),
Transform::FormatInteger(i, s) => write!(f, "format-integer({:?}, {:?})", i, s),
Transform::GenerateIntegers(_start_at, _select, _n) => write!(f, "generate-integers"),
Transform::CurrentGroup => write!(f, "current-group"),
Transform::CurrentGroupingKey => write!(f, "current-grouping-key"),
Transform::Key(s, _, _, _) => write!(f, "key({:?}, ...)", s),
Transform::SystemProperty(p, _) => write!(f, "system-properties({:?})", p),
Transform::AvailableSystemProperties => write!(f, "available-system-properties"),
Transform::Document(uris, _) => write!(f, "document({:?})", uris),
Transform::Invoke(qn, _a, _) => write!(f, "invoke \"{}\"", qn),
Transform::Message(_, _, _, _) => write!(f, "message"),
Transform::NotImplemented(s) => write!(f, "Not implemented: \"{}\"", s),
Transform::Error(k, s) => write!(f, "Error: {} \"{}\"", k, s),
}
}
}
pub fn in_scope_namespaces<N: Node>(n: Option<N>) -> Rc<NamespaceMap> {
if let Some(nn) = n {
Rc::new(nn.namespace_iter().fold(NamespaceMap::new(), |mut hm, ns| {
hm.push(
NamespaceDeclaration::new(
ns.name().map(|nsprefix| {
NamespacePrefix::try_from(nsprefix.local_name().to_string().as_str())
.unwrap()
}),
NamespaceUri::try_from(ns.value().to_string().as_str()).unwrap(),
)
.unwrap(),
);
hm
}))
} else {
Rc::new(NamespaceMap::new())
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum Order {
Ascending,
Descending,
}
pub(crate) fn do_sort<
N: Node,
F: FnMut(&str) -> Result<(), Error>,
G: FnMut(&str) -> Result<N, Error>,
H: FnMut(&Url) -> Result<String, Error>,
>(
seq: &mut Sequence<N>,
o: &Vec<(Order, Transform<N>)>,
ctxt: &Context<N>,
stctxt: &mut StaticContext<N, F, G, H>,
) -> Result<(), Error> {
if !o.is_empty() {
seq.sort_by_cached_key(|k| {
let key_seq = ContextBuilder::from(ctxt)
.context(vec![k.clone()])
.build()
.dispatch(stctxt, &o[0].1)
.expect("unable to determine key value");
key_seq.to_string()
});
if o[0].0 == Order::Descending {
seq.reverse();
}
}
Ok(())
}
#[derive(Clone, Debug)]
pub enum Grouping<N: Node> {
By(Vec<Transform<N>>),
StartingWith(Box<Pattern<N>>),
EndingWith(Box<Pattern<N>>),
Adjacent(Vec<Transform<N>>),
}
impl<N: Node> Grouping<N> {
fn to_string(&self) -> String {
match self {
Grouping::By(_) => "group-by".to_string(),
Grouping::Adjacent(_) => "group-adjacent".to_string(),
Grouping::StartingWith(_) => "group-starting-with".to_string(),
Grouping::EndingWith(_) => "group-ending-with".to_string(),
}
}
}
impl<N: Node> fmt::Display for Grouping<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_string())
}
}
#[derive(Clone, Debug)]
pub struct NodeMatch {
pub axis: Axis,
pub nodetest: NodeTest,
}
impl NodeMatch {
pub fn new(axis: Axis, nodetest: NodeTest) -> Self {
NodeMatch { axis, nodetest }
}
pub fn matches_item<N: Node>(&self, i: &Item<N>) -> bool {
match i {
Item::Node(n) => self.matches(n),
_ => false,
}
}
pub fn matches<N: Node>(&self, n: &N) -> bool {
self.nodetest.matches(n)
}
}
impl fmt::Display for NodeMatch {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "node match {} {}", self.axis, self.nodetest)
}
}
#[derive(Clone, Debug)]
pub enum NodeTest {
Kind(KindTest),
Name(NameTest),
}
impl NodeTest {
pub fn matches_item<N: Node>(&self, i: &Item<N>) -> bool {
match i {
Item::Node(n) => self.matches(n),
_ => false,
}
}
pub fn matches<N: Node>(&self, n: &N) -> bool {
match self {
NodeTest::Kind(k) => k.matches(n),
NodeTest::Name(nm) => nm.matches(n),
}
}
}
impl fmt::Display for NodeTest {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
NodeTest::Kind(k) => write!(f, "kind test {}", k),
NodeTest::Name(nm) => write!(f, "name test {}", nm),
}
}
}
impl TryFrom<&str> for NodeTest {
type Error = Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
let tok: Vec<&str> = s.split(':').collect();
match tok.len() {
1 => {
if tok[0] == "*" {
Ok(NodeTest::Name(NameTest::Wildcard(
WildcardOrNamespaceUri::Wildcard,
WildcardOrName::Wildcard,
)))
} else {
Ok(NodeTest::Name(NameTest::Name(QName::from_local_name(
NcName::try_from(tok[0])
.map_err(|_| Error::new(ErrorKind::ParseError, "not a NcName"))?,
))))
}
}
2 => {
if tok[0] == "*" {
if tok[1] == "*" {
Ok(NodeTest::Name(NameTest::Wildcard(
WildcardOrNamespaceUri::Wildcard,
WildcardOrName::Wildcard,
)))
} else {
Ok(NodeTest::Name(NameTest::Wildcard(
WildcardOrNamespaceUri::Wildcard,
WildcardOrName::Name(QName::from_local_name(
NcName::try_from(tok[1]).map_err(|_| {
Error::new(ErrorKind::ParseError, "not a NcName")
})?,
)),
)))
}
} else if tok[1] == "*" {
Ok(NodeTest::Name(NameTest::Wildcard(
WildcardOrNamespaceUri::NamespaceUri(
NamespaceUri::try_from(tok[0]).map_err(|_| {
Error::new(ErrorKind::ParseError, "not a namespace URI")
})?,
),
WildcardOrName::Wildcard,
)))
} else {
Ok(NodeTest::Name(NameTest::Name(QName::new_from_parts(
NcName::try_from(tok[1])
.map_err(|_| Error::new(ErrorKind::ParseError, "not a NcName"))?,
Some(
NamespaceUri::try_from(tok[1])
.map_err(|_| Error::new(ErrorKind::ParseError, "not a NcName"))?,
),
))))
}
}
_ => Result::Err(Error::new(
ErrorKind::TypeError,
"invalid NodeTest".to_string(),
)),
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum KindTest {
Document,
Element,
Attribute,
SchemaElement,
SchemaAttribute,
PI,
Comment,
Text,
Namespace,
Any,
}
impl fmt::Display for KindTest {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
KindTest::Document => write!(f, "document"),
KindTest::Element => write!(f, "element"),
KindTest::Attribute => write!(f, "attribute"),
KindTest::SchemaElement => write!(f, "schema element"),
KindTest::SchemaAttribute => write!(f, "schema attribute"),
KindTest::PI => write!(f, "processing instruction"),
KindTest::Comment => write!(f, "comment"),
KindTest::Text => write!(f, "text"),
KindTest::Namespace => write!(f, "namespace"),
KindTest::Any => write!(f, "any node"),
}
}
}
impl KindTest {
pub fn matches_item<N: Node>(&self, i: &Item<N>) -> bool {
match i {
Item::Node(n) => self.matches(n),
_ => false,
}
}
pub fn matches<N: Node>(&self, n: &N) -> bool {
match (self, n.node_type()) {
(KindTest::Document, NodeType::Document) => true,
(KindTest::Document, _) => false,
(KindTest::Element, NodeType::Element) => true,
(KindTest::Element, _) => false,
(KindTest::Attribute, NodeType::Attribute) => true,
(KindTest::Attribute, _) => false,
(KindTest::SchemaElement, _) => false, (KindTest::SchemaAttribute, _) => false, (KindTest::PI, NodeType::ProcessingInstruction) => true,
(KindTest::PI, _) => false,
(KindTest::Comment, NodeType::Comment) => true,
(KindTest::Comment, _) => false,
(KindTest::Text, NodeType::Text) => true,
(KindTest::Text, _) => false,
(KindTest::Namespace, _) => false, (KindTest::Any, _) => true,
}
}
pub fn to_string(&self) -> &'static str {
match self {
KindTest::Document => "DocumentTest",
KindTest::Element => "ElementTest",
KindTest::Attribute => "AttributeTest",
KindTest::SchemaElement => "SchemaElementTest",
KindTest::SchemaAttribute => "SchemaAttributeTest",
KindTest::PI => "PITest",
KindTest::Comment => "CommentTest",
KindTest::Text => "TextTest",
KindTest::Namespace => "NamespaceNodeTest",
KindTest::Any => "AnyKindTest",
}
}
}
#[derive(Clone, Debug)]
pub enum NameTest {
Name(QName),
Wildcard(WildcardOrNamespaceUri, WildcardOrName),
}
impl NameTest {
pub fn matches_item<N: Node>(&self, i: &Item<N>) -> bool {
match i {
Item::Node(n) => self.matches(n),
_ => false, }
}
pub fn matches<N: Node>(&self, n: &N) -> bool {
if let Some(nm) = n.name() {
match self {
NameTest::Name(qn) => *qn == nm,
NameTest::Wildcard(nsw, nmw) => {
let nsb = match nsw {
WildcardOrNamespaceUri::Wildcard => true,
WildcardOrNamespaceUri::NamespaceUri(nsuri) => {
nm.namespace_uri().is_some_and(|ns| *nsuri == ns)
}
};
let nmb = match nmw {
WildcardOrName::Wildcard => true,
WildcardOrName::Name(nmwn) => nmwn.local_name() == nm.local_name(),
};
nsb && nmb
}
}
} else {
false
}
}
}
impl fmt::Display for NameTest {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
NameTest::Name(nm) => f.write_str(nm.to_string().as_str()),
NameTest::Wildcard(nsw, nmw) => {
let _ = f.write_str("{");
let _ = match nsw {
WildcardOrNamespaceUri::NamespaceUri(nsuri) => {
f.write_str(nsuri.to_string().as_str())
}
WildcardOrNamespaceUri::Wildcard => f.write_str("*"),
};
let _ = f.write_str("}");
match nmw {
WildcardOrName::Wildcard => f.write_str("*"),
WildcardOrName::Name(n) => f.write_str(n.to_string().as_str()),
}
}
}
}
}
#[derive(Clone)]
pub enum WildcardOrNamespaceUri {
Wildcard,
NamespaceUri(NamespaceUri),
}
impl Debug for WildcardOrNamespaceUri {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
WildcardOrNamespaceUri::Wildcard => f.write_str("WildcardOrNamespaceUri::Wildcard"),
WildcardOrNamespaceUri::NamespaceUri(ns) => f.write_str(
format!("WildcardOrNamespaceUri::NamespaceUri({})", ns.to_string()).as_str(),
),
}
}
}
#[derive(Clone)]
pub enum WildcardOrName {
Wildcard,
Name(QName), }
impl Debug for WildcardOrName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
WildcardOrName::Wildcard => f.write_str("WildcardOrNamespaceUri::Wildcard"),
WildcardOrName::Name(n) => f.write_str(format!("WildcardOrName::Name({})", n).as_str()),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Axis {
Child,
Descendant,
DescendantOrSelf,
DescendantOrSelfOrRoot,
Attribute,
SelfAttribute, SelfAxis,
SelfDocument, SelfNamespace, Following,
FollowingSibling,
Namespace,
Parent,
ParentDocument, Ancestor,
AncestorOrSelf,
AncestorOrSelfOrRoot, Preceding,
PrecedingSibling,
Unknown,
}
impl From<&str> for Axis {
fn from(s: &str) -> Self {
match s {
"child" => Axis::Child,
"descendant" => Axis::Descendant,
"descendant-or-self" => Axis::DescendantOrSelf,
"attribute" => Axis::Attribute,
"self" => Axis::SelfAxis,
"following" => Axis::Following,
"following-sibling" => Axis::FollowingSibling,
"namespace" => Axis::Namespace,
"parent" => Axis::Parent,
"ancestor" => Axis::Ancestor,
"ancestor-or-self" => Axis::AncestorOrSelf,
"preceding" => Axis::Preceding,
"preceding-sibling" => Axis::PrecedingSibling,
_ => Axis::Unknown,
}
}
}
impl fmt::Display for Axis {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let result = match self {
Axis::Child => "child".to_string(),
Axis::Descendant => "descendant".to_string(),
Axis::DescendantOrSelf => "descendant-or-self".to_string(),
Axis::DescendantOrSelfOrRoot => "descendant-or-self-or-root".to_string(),
Axis::Attribute => "attribute".to_string(),
Axis::SelfAttribute => "self-attribute".to_string(),
Axis::SelfAxis => "self".to_string(),
Axis::SelfDocument => "self-document".to_string(),
Axis::Following => "following".to_string(),
Axis::FollowingSibling => "following-sibling".to_string(),
Axis::Namespace => "namespace".to_string(),
Axis::Parent => "parent".to_string(),
Axis::ParentDocument => "parent-document".to_string(),
Axis::Ancestor => "ancestor".to_string(),
Axis::AncestorOrSelf => "ancestor-or-self".to_string(),
Axis::Preceding => "preceding".to_string(),
Axis::PrecedingSibling => "preceding-sibling".to_string(),
_ => "unknown".to_string(),
};
f.write_str(result.as_str())
}
}
#[derive(Clone, Debug)]
pub struct ArithmeticOperand<N: Node> {
pub op: ArithmeticOperator,
pub operand: Transform<N>,
}
impl<N: Node> ArithmeticOperand<N> {
pub fn new(op: ArithmeticOperator, operand: Transform<N>) -> Self {
ArithmeticOperand { op, operand }
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ArithmeticOperator {
Noop,
Add,
Multiply,
Divide,
IntegerDivide,
Subtract,
Modulo,
}
impl fmt::Display for ArithmeticOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ArithmeticOperator::Add => f.write_str("+"),
ArithmeticOperator::Multiply => f.write_str("*"),
ArithmeticOperator::Divide => f.write_str("div"),
ArithmeticOperator::IntegerDivide => f.write_str("idiv"),
ArithmeticOperator::Subtract => f.write_str("-"),
ArithmeticOperator::Modulo => f.write_str("mod"),
ArithmeticOperator::Noop => f.write_str("noop"),
}
}
}
impl From<&str> for ArithmeticOperator {
fn from(a: &str) -> Self {
match a {
"+" => ArithmeticOperator::Add,
"*" => ArithmeticOperator::Multiply,
"div" => ArithmeticOperator::Divide,
"idiv" => ArithmeticOperator::IntegerDivide,
"-" => ArithmeticOperator::Subtract,
"mod" => ArithmeticOperator::Modulo,
_ => ArithmeticOperator::Noop,
}
}
}
impl From<String> for ArithmeticOperator {
fn from(a: String) -> Self {
match a.as_str() {
"+" => ArithmeticOperator::Add,
"*" => ArithmeticOperator::Multiply,
"div" => ArithmeticOperator::Divide,
"idiv" => ArithmeticOperator::IntegerDivide,
"-" => ArithmeticOperator::Subtract,
"mod" => ArithmeticOperator::Modulo,
_ => ArithmeticOperator::Noop,
}
}
}