1use markup5ever::{LocalName, Namespace, Prefix, QualName};
6
7use crate::NamespaceResolver;
8use crate::ast::{
9 Axis, BinaryOperator, CoreFunction, Expression, FilterExpression, KindTest, Literal,
10 LocationStepExpression, NodeTest, PathExpression, PredicateListExpression,
11};
12use crate::tokenizer::{Error as TokenizerError, LiteralToken, OperatorToken, Token, tokenize};
13
14#[derive(Clone, Debug)]
15pub enum Error {
16 Tokenization(TokenizerError),
17 UnknownFunction,
18 ExpectedSeperatorBetweenFunctionArguments,
19 TooFewFunctionArguments,
20 TooManyFunctionArguments,
21 ExpectedClosingParenthesis,
22 ExpectedClosingBracket,
23 CannotUseVariables,
24 UnknownAxis,
25 TrailingInput,
26 UnknownNodeTest,
27 ExpectedNodeTest,
28 UnexpectedEndOfInput,
29 FailedToResolveNamespacePrefix,
30}
31
32impl From<TokenizerError> for Error {
33 fn from(value: TokenizerError) -> Self {
34 Self::Tokenization(value)
35 }
36}
37
38pub fn parse<N>(
40 cx: &mut N::Context,
41 input: &str,
42 namespace_resolver: Option<N>,
43 is_in_html_document: bool,
44) -> Result<Expression, Error>
45where
46 N: NamespaceResolver,
47{
48 let mut parser = Parser::new(input, namespace_resolver, is_in_html_document)?;
49 let root_expression = parser.parse_expression(cx)?;
50 if !parser.remaining().is_empty() {
51 log::debug!(
52 "Found trailing tokens after expression: {:?}",
53 parser.remaining()
54 );
55 return Err(Error::TrailingInput);
56 }
57
58 log::debug!("Parsed XPath expression: {root_expression:?}");
59 Ok(root_expression)
60}
61
62pub(crate) struct Parser<'a, N>
63where
64 N: NamespaceResolver,
65{
66 tokens: Vec<Token<'a>>,
67 position: usize,
68 namespace_resolver: Option<N>,
69 is_in_html_document: bool,
70}
71
72impl<'a, N> Parser<'a, N>
73where
74 N: NamespaceResolver,
75{
76 pub(crate) fn new(
77 input: &'a str,
78 namespace_resolver: Option<N>,
79 is_in_html_document: bool,
80 ) -> Result<Self, TokenizerError> {
81 let parser = Self {
82 tokens: tokenize(input)?,
83 position: 0,
84 namespace_resolver,
85 is_in_html_document,
86 };
87 Ok(parser)
88 }
89
90 fn expect_current_token(&self) -> Result<Token<'a>, Error> {
91 self.tokens
92 .get(self.position)
93 .copied()
94 .ok_or(Error::UnexpectedEndOfInput)
95 }
96
97 fn peek(&self, n: usize) -> Option<Token<'a>> {
98 self.tokens.get(self.position + n).copied()
99 }
100
101 fn advance(&mut self, advance_by: usize) {
102 self.position += advance_by;
103 }
104
105 pub(crate) fn remaining(&self) -> &[Token<'a>] {
106 &self.tokens[self.position..]
107 }
108
109 fn resolve_qualified_name(
110 &self,
111 cx: &mut N::Context,
112 prefix: &str,
113 ) -> Result<Namespace, Error> {
114 let Some(namespace_resolver) = self.namespace_resolver.as_ref() else {
115 return Err(Error::FailedToResolveNamespacePrefix);
116 };
117
118 log::debug!("Resolving namespace prefix: {:?}", prefix);
119 namespace_resolver
120 .resolve_namespace_prefix(cx, prefix)
121 .map(Namespace::from)
122 .ok_or(Error::FailedToResolveNamespacePrefix)
123 }
124
125 fn advance_if_current_token_equals(&mut self, wanted: Token<'a>) -> bool {
126 if self.peek(0).is_some_and(|token| token == wanted) {
127 self.position += 1;
128 true
129 } else {
130 false
131 }
132 }
133
134 pub(crate) fn parse_expression(&mut self, cx: &mut N::Context) -> Result<Expression, Error> {
135 let mut result;
136
137 let mut expression_stack: Vec<(Expression, OperatorToken)> = vec![];
138 loop {
139 let mut negations = 0;
140 while self.advance_if_current_token_equals(Token::Operator(OperatorToken::Subtract)) {
141 negations += 1;
142 }
143
144 result = self.parse_union_expression(cx)?;
145
146 if negations > 1 {
147 if negations % 2 == 0 {
148 result = Expression::Function(CoreFunction::Number(Some(Box::new(result))))
149 } else {
150 result = Expression::Negate(Box::new(result))
151 }
152 }
153
154 let Some(next_token) = self.peek(0) else {
156 break;
157 };
158 let Token::Operator(current_operator) = next_token else {
159 break;
160 };
161 self.advance(1);
162
163 while let Some((lhs, operator)) = expression_stack
165 .pop_if(|(_, operator)| current_operator.precedence() <= operator.precedence())
166 {
167 result = create_binary_expression(Box::new(lhs), operator, Box::new(result));
168 }
169
170 expression_stack.push((result, current_operator));
171 }
172
173 for (lhs, operator) in expression_stack.into_iter().rev() {
175 result = create_binary_expression(Box::new(lhs), operator, Box::new(result))
176 }
177
178 Ok(result)
179 }
180
181 fn parse_union_expression(&mut self, cx: &mut N::Context) -> Result<Expression, Error> {
183 let mut result = self.parse_path_expression(cx)?;
184
185 while self.advance_if_current_token_equals(Token::Union) {
186 let rhs = self.parse_path_expression(cx)?;
187 result = Expression::Binary(Box::new(result), BinaryOperator::Union, Box::new(rhs));
188 }
189
190 Ok(result)
191 }
192
193 fn parse_path_expression(&mut self, cx: &mut N::Context) -> Result<Expression, Error> {
195 let current_token = self.expect_current_token()?;
196
197 let is_absolute = matches!(current_token, Token::Parent | Token::Ancestor);
198 let has_implicit_descendant_or_self_step = current_token == Token::Ancestor;
199
200 if is_absolute {
201 self.advance(1);
202
203 if !self
204 .peek(0)
205 .is_some_and(|token| token.is_start_of_location_step())
206 {
207 return Ok(Expression::Path(PathExpression {
208 is_absolute,
209 has_implicit_descendant_or_self_step,
210 steps: vec![],
211 }));
212 }
213 }
214
215 let first_expression = if !is_absolute {
216 let expression = self.parse_filter_or_step_expression(cx)?;
217
218 if !self
220 .peek(0)
221 .is_some_and(|token| matches!(token, Token::Parent | Token::Ancestor))
222 {
223 return Ok(expression);
224 }
225
226 expression
227 } else {
228 self.parse_step_expression(cx)?
229 };
230
231 let mut path_expression = PathExpression {
232 is_absolute,
233 has_implicit_descendant_or_self_step,
234 steps: vec![first_expression],
235 };
236
237 while let Some(current_token) = self.peek(0) {
238 match current_token {
239 Token::Ancestor => {
240 self.advance(1);
241
242 path_expression
244 .steps
245 .push(Expression::LocationStep(LocationStepExpression {
246 axis: Axis::DescendantOrSelf,
247 node_test: NodeTest::Kind(KindTest::Node),
248 predicate_list: PredicateListExpression { predicates: vec![] },
249 }));
250 true
251 },
252 Token::Parent => {
253 self.advance(1);
254 false
255 },
256 _ => {
257 return Ok(Expression::Path(path_expression));
259 },
260 };
261
262 let step_expression = self.parse_step_expression(cx)?;
263 path_expression.steps.push(step_expression);
264 }
265
266 Ok(Expression::Path(path_expression))
267 }
268
269 fn parse_filter_or_step_expression(
273 &mut self,
274 cx: &mut N::Context,
275 ) -> Result<Expression, Error> {
276 let mut expression = match self.expect_current_token()? {
277 Token::FunctionCall(name) => {
278 self.advance(1);
279 self.parse_function_call(cx, name)?
280 },
281 Token::OpeningParenthesis => {
282 self.advance(1);
283 let expression = self.parse_expression(cx)?;
284 if !self.advance_if_current_token_equals(Token::ClosingParenthesis) {
285 log::debug!("{:?}", self.expect_current_token()?);
286 return Err(Error::ExpectedClosingParenthesis);
287 }
288 expression
289 },
290 Token::Literal(literal) => {
291 self.advance(1);
292 Expression::Literal(literal.into())
293 },
294 Token::VariableReference(_) => {
295 return Err(Error::CannotUseVariables);
298 },
299 _ => self.parse_step_expression(cx)?,
300 };
301
302 let predicate_list = self.parse_predicates(cx)?;
304 if !predicate_list.predicates.is_empty() {
305 expression = Expression::Filter(FilterExpression {
306 expression: Box::new(expression),
307 predicates: predicate_list,
308 });
309 }
310
311 Ok(expression)
312 }
313
314 fn parse_step_expression(&mut self, cx: &mut N::Context) -> Result<Expression, Error> {
316 let axis;
317 let mut node_test = None;
318
319 match self.expect_current_token()? {
320 Token::AxisIdentifier(axis_name) => {
321 self.advance(1);
322 axis = match axis_name {
323 "ancestor" => Axis::Ancestor,
324 "ancestor-or-self" => Axis::AncestorOrSelf,
325 "attribute" => Axis::Attribute,
326 "child" => Axis::Child,
327 "descendant" => Axis::Descendant,
328 "descendant-or-self" => Axis::DescendantOrSelf,
329 "following" => Axis::Following,
330 "following-sibling" => Axis::FollowingSibling,
331 "namespace" => Axis::Namespace,
332 "parent" => Axis::Parent,
333 "preceding" => Axis::Preceding,
334 "preceding-sibling" => Axis::PrecedingSibling,
335 "self" => Axis::Self_,
336 _ => {
337 log::debug!("Unknown XPath axis name: {axis_name:?}");
338 return Err(Error::UnknownAxis);
339 },
340 };
341 },
342 Token::AtSign => {
343 self.advance(1);
345 axis = Axis::Attribute;
346 },
347 Token::ParentNode => {
348 self.advance(1);
349 axis = Axis::Parent;
350 node_test = Some(NodeTest::Kind(KindTest::Node));
351 },
352 Token::SelfNode => {
353 self.advance(1);
354 axis = Axis::Self_;
355 node_test = Some(NodeTest::Kind(KindTest::Node));
356 },
357 _ => {
358 axis = Axis::Child;
359 },
360 }
361
362 let node_test = if let Some(node_test) = node_test {
363 node_test
364 } else if let Token::CName(name_token) = self.expect_current_token()? {
365 self.advance(1);
366
367 if name_token.local_name == "*" {
368 NodeTest::Wildcard
369 } else {
370 let namespace = name_token
371 .prefix
372 .map(|prefix| self.resolve_qualified_name(cx, prefix))
373 .transpose()?;
374
375 let local_name = if self.is_in_html_document && name_token.prefix.is_none() {
376 LocalName::from(name_token.local_name.to_ascii_lowercase().as_str())
377 } else {
378 LocalName::from(name_token.local_name)
379 };
380
381 let qualified_name = QualName {
382 prefix: name_token.prefix.map(Prefix::from),
383 ns: namespace.unwrap_or_default(),
384 local: local_name,
385 };
386
387 NodeTest::Name(qualified_name)
388 }
389 } else {
390 self.parse_node_test()?
391 };
392
393 let predicate_list = self.parse_predicates(cx)?;
394 Ok(Expression::LocationStep(LocationStepExpression {
395 axis,
396 node_test,
397 predicate_list,
398 }))
399 }
400
401 fn parse_node_test(&mut self) -> Result<NodeTest, Error> {
402 let kind_test = match self.expect_current_token()? {
403 Token::CommentTest => {
404 self.advance(1);
405 KindTest::Comment
406 },
407 Token::NodeTest => {
408 self.advance(1);
409 KindTest::Node
410 },
411 Token::ProcessingInstructionTest => {
412 self.advance(1);
413 let name = if let Token::Literal(LiteralToken::String(name)) =
414 self.expect_current_token()?
415 {
416 self.advance(1);
417 Some(name)
418 } else {
419 None
420 };
421 KindTest::PI(name.map(String::from))
422 },
423 Token::TextTest => {
424 self.advance(1);
425 KindTest::Text
426 },
427 _ => {
428 return Err(Error::ExpectedNodeTest);
429 },
430 };
431
432 if !self.advance_if_current_token_equals(Token::ClosingParenthesis) {
433 return Err(Error::TooManyFunctionArguments);
434 }
435
436 Ok(NodeTest::Kind(kind_test))
437 }
438
439 fn parse_predicates(&mut self, cx: &mut N::Context) -> Result<PredicateListExpression, Error> {
441 let mut predicates = vec![];
442 while self.advance_if_current_token_equals(Token::OpeningBracket) {
443 let expression = self.parse_expression(cx)?;
444 predicates.push(expression);
445 if !self.advance_if_current_token_equals(Token::ClosingBracket) {
446 return Err(Error::ExpectedClosingBracket);
447 }
448 }
449 Ok(PredicateListExpression { predicates })
450 }
451
452 fn parse_function_call(
453 &mut self,
454 cx: &mut N::Context,
455 function_name: &str,
456 ) -> Result<Expression, Error> {
457 struct ArgumentIterator<'a, 'b, N>
458 where
459 N: NamespaceResolver,
460 {
461 parser: &'b mut Parser<'a, N>,
462 done: bool,
463 }
464
465 impl<'a, 'b, N> ArgumentIterator<'a, 'b, N>
466 where
467 N: NamespaceResolver,
468 {
469 fn maybe_next(&mut self, cx: &mut N::Context) -> Result<Option<Expression>, Error> {
470 if self.done {
471 return Ok(None);
472 }
473 let expression = self.parser.parse_expression(cx)?;
474 if self
475 .parser
476 .advance_if_current_token_equals(Token::ClosingParenthesis)
477 {
478 self.done = true;
479 } else if !self.parser.advance_if_current_token_equals(Token::Comma) {
480 log::debug!("{:?}", self.parser.peek(0));
481 return Err(Error::ExpectedSeperatorBetweenFunctionArguments);
482 }
483
484 Ok(Some(expression))
485 }
486
487 fn next(&mut self, cx: &mut N::Context) -> Result<Expression, Error> {
488 self.maybe_next(cx)
489 .and_then(|maybe_argument| maybe_argument.ok_or(Error::TooFewFunctionArguments))
490 }
491 }
492
493 let mut arguments = ArgumentIterator {
494 done: self.advance_if_current_token_equals(Token::ClosingParenthesis),
495 parser: self,
496 };
497
498 let core_fn = match function_name {
499 "last" => CoreFunction::Last,
501 "position" => CoreFunction::Position,
502 "count" => CoreFunction::Count(Box::new(arguments.next(cx)?)),
503 "id" => CoreFunction::Id(Box::new(arguments.next(cx)?)),
504 "local-name" => CoreFunction::LocalName(arguments.maybe_next(cx)?.map(Box::new)),
505 "namespace-uri" => CoreFunction::NamespaceUri(arguments.maybe_next(cx)?.map(Box::new)),
506 "name" => CoreFunction::Name(arguments.maybe_next(cx)?.map(Box::new)),
507
508 "string" => CoreFunction::String(arguments.maybe_next(cx)?.map(Box::new)),
510 "concat" => {
511 let mut args = vec![];
512 while let Some(argument) = arguments.maybe_next(cx)? {
513 args.push(argument);
514 }
515 CoreFunction::Concat(args)
516 },
517 "starts-with" => CoreFunction::StartsWith(
518 Box::new(arguments.next(cx)?),
519 Box::new(arguments.next(cx)?),
520 ),
521 "contains" => {
522 CoreFunction::Contains(Box::new(arguments.next(cx)?), Box::new(arguments.next(cx)?))
523 },
524 "substring-before" => CoreFunction::SubstringBefore(
525 Box::new(arguments.next(cx)?),
526 Box::new(arguments.next(cx)?),
527 ),
528 "substring-after" => CoreFunction::SubstringAfter(
529 Box::new(arguments.next(cx)?),
530 Box::new(arguments.next(cx)?),
531 ),
532 "substring" => CoreFunction::Substring(
533 Box::new(arguments.next(cx)?),
534 Box::new(arguments.next(cx)?),
535 arguments.maybe_next(cx)?.map(Box::new),
536 ),
537 "string-length" => CoreFunction::StringLength(arguments.maybe_next(cx)?.map(Box::new)),
538 "normalize-space" => {
539 CoreFunction::NormalizeSpace(arguments.maybe_next(cx)?.map(Box::new))
540 },
541 "translate" => CoreFunction::Translate(
542 Box::new(arguments.next(cx)?),
543 Box::new(arguments.next(cx)?),
544 Box::new(arguments.next(cx)?),
545 ),
546
547 "number" => CoreFunction::Number(arguments.maybe_next(cx)?.map(Box::new)),
549 "sum" => CoreFunction::Sum(Box::new(arguments.next(cx)?)),
550 "floor" => CoreFunction::Floor(Box::new(arguments.next(cx)?)),
551 "ceiling" => CoreFunction::Ceiling(Box::new(arguments.next(cx)?)),
552 "round" => CoreFunction::Round(Box::new(arguments.next(cx)?)),
553
554 "boolean" => CoreFunction::Boolean(Box::new(arguments.next(cx)?)),
556 "not" => CoreFunction::Not(Box::new(arguments.next(cx)?)),
557 "true" => CoreFunction::True,
558 "false" => CoreFunction::False,
559 "lang" => CoreFunction::Lang(Box::new(arguments.next(cx)?)),
560
561 _ => return Err(Error::UnknownFunction),
563 };
564
565 if !arguments.done {
567 return Err(Error::TooManyFunctionArguments);
568 }
569
570 Ok(Expression::Function(core_fn))
571 }
572}
573
574fn create_binary_expression(
575 lhs: Box<Expression>,
576 operator: OperatorToken,
577 rhs: Box<Expression>,
578) -> Expression {
579 let binary_operator = match operator {
580 OperatorToken::And => BinaryOperator::And,
581 OperatorToken::Or => BinaryOperator::Or,
582 OperatorToken::Multiply => BinaryOperator::Multiply,
583 OperatorToken::Divide => BinaryOperator::Divide,
584 OperatorToken::Modulo => BinaryOperator::Modulo,
585 OperatorToken::Add => BinaryOperator::Add,
586 OperatorToken::Subtract => BinaryOperator::Subtract,
587 OperatorToken::Equal => BinaryOperator::Equal,
588 OperatorToken::NotEqual => BinaryOperator::NotEqual,
589 OperatorToken::GreaterThan => BinaryOperator::GreaterThan,
590 OperatorToken::GreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual,
591 OperatorToken::LessThan => BinaryOperator::LessThan,
592 OperatorToken::LessThanOrEqual => BinaryOperator::LessThanOrEqual,
593 };
594
595 Expression::Binary(lhs, binary_operator, rhs)
596}
597
598impl<'a> From<LiteralToken<'a>> for Literal {
599 fn from(value: LiteralToken<'a>) -> Self {
600 match value {
601 LiteralToken::Integer(integer) => Self::Integer(integer),
602 LiteralToken::Decimal(float) => Self::Decimal(float),
603 LiteralToken::String(string) => Self::String(string.to_owned()),
604 }
605 }
606}
607
608#[cfg(test)]
610mod tests {
611 use markup5ever::{LocalName, QualName, local_name, namespace_prefix, ns};
612
613 use super::*;
614 use crate::NamespaceResolver;
615
616 #[derive(Clone)]
617 struct DummyNamespaceResolver;
618
619 impl NamespaceResolver for DummyNamespaceResolver {
620 type Context = ();
621
622 fn resolve_namespace_prefix(&self, _: &mut (), _: &str) -> Option<String> {
623 Some("http://www.w3.org/1999/xhtml".to_owned())
624 }
625 }
626
627 #[test]
628 fn test_filter_expr() {
629 let cases = vec![
630 (
631 "processing-instruction('test')[2]",
632 Expression::LocationStep(LocationStepExpression {
633 axis: Axis::Child,
634 node_test: NodeTest::Kind(KindTest::PI(Some("test".to_string()))),
635 predicate_list: PredicateListExpression {
636 predicates: vec![Expression::Literal(Literal::Integer(2))],
637 },
638 }),
639 ),
640 (
641 "concat('hello', ' ', 'world')",
642 Expression::Function(CoreFunction::Concat(vec![
643 Expression::Literal(Literal::String("hello".to_string())),
644 Expression::Literal(Literal::String(" ".to_string())),
645 Expression::Literal(Literal::String("world".to_string())),
646 ])),
647 ),
648 ];
649
650 for (input, expected) in cases {
651 match parse(&mut (), input, Some(DummyNamespaceResolver), true) {
652 Ok(result) => {
653 assert_eq!(result, expected, "{:?} was parsed incorrectly", input);
654 },
655 Err(e) => panic!("Failed to parse '{}': {:?}", input, e),
656 }
657 }
658 }
659
660 #[test]
661 fn test_complex_paths() {
662 let cases = vec![
663 (
664 "//*[contains(@class, 'test')]",
665 Expression::Path(PathExpression {
666 is_absolute: true,
667 has_implicit_descendant_or_self_step: true,
668 steps: vec![Expression::LocationStep(LocationStepExpression {
669 axis: Axis::Child,
670 node_test: NodeTest::Wildcard,
671 predicate_list: PredicateListExpression {
672 predicates: vec![Expression::Function(CoreFunction::Contains(
673 Box::new(Expression::LocationStep(LocationStepExpression {
674 axis: Axis::Attribute,
675 node_test: NodeTest::Name(QualName {
676 prefix: None,
677 ns: ns!(),
678 local: local_name!("class"),
679 }),
680 predicate_list: PredicateListExpression { predicates: vec![] },
681 })),
682 Box::new(Expression::Literal(Literal::String("test".to_owned()))),
683 ))],
684 },
685 })],
686 }),
687 ),
688 (
689 "//div[position() > 1]/*[last()]",
690 Expression::Path(PathExpression {
691 is_absolute: true,
692 has_implicit_descendant_or_self_step: true,
693 steps: vec![
694 Expression::LocationStep(LocationStepExpression {
695 axis: Axis::Child,
696 node_test: NodeTest::Name(QualName {
697 prefix: None,
698 ns: ns!(),
699 local: local_name!("div"),
700 }),
701 predicate_list: PredicateListExpression {
702 predicates: vec![Expression::Binary(
703 Box::new(Expression::Function(CoreFunction::Position)),
704 BinaryOperator::GreaterThan,
705 Box::new(Expression::Literal(Literal::Integer(1))),
706 )],
707 },
708 }),
709 Expression::LocationStep(LocationStepExpression {
710 axis: Axis::Child,
711 node_test: NodeTest::Wildcard,
712 predicate_list: PredicateListExpression {
713 predicates: vec![Expression::Function(CoreFunction::Last)],
714 },
715 }),
716 ],
717 }),
718 ),
719 (
720 "//mu[@xml:id=\"id1\"]//rho[@title][@xml:lang=\"en-GB\"]",
721 Expression::Path(PathExpression {
722 is_absolute: true,
723 has_implicit_descendant_or_self_step: true,
724 steps: vec![
725 Expression::LocationStep(LocationStepExpression {
726 axis: Axis::Child,
727 node_test: NodeTest::Name(QualName {
728 prefix: None,
729 ns: ns!(),
730 local: LocalName::from("mu"),
731 }),
732 predicate_list: PredicateListExpression {
733 predicates: vec![Expression::Binary(
734 Box::new(Expression::LocationStep(LocationStepExpression {
735 axis: Axis::Attribute,
736 node_test: NodeTest::Name(QualName {
737 prefix: Some(namespace_prefix!("xml")),
738 ns: ns!(html),
739 local: local_name!("id"),
740 }),
741 predicate_list: PredicateListExpression {
742 predicates: vec![],
743 },
744 })),
745 BinaryOperator::Equal,
746 Box::new(Expression::Literal(Literal::String(
747 "id1".to_owned(),
748 ))),
749 )],
750 },
751 }),
752 Expression::LocationStep(LocationStepExpression {
753 axis: Axis::DescendantOrSelf,
754 node_test: NodeTest::Kind(KindTest::Node),
755 predicate_list: PredicateListExpression { predicates: vec![] },
756 }),
757 Expression::LocationStep(LocationStepExpression {
758 axis: Axis::Child,
759 node_test: NodeTest::Name(QualName {
760 prefix: None,
761 ns: ns!(),
762 local: LocalName::from("rho"),
763 }),
764 predicate_list: PredicateListExpression {
765 predicates: vec![
766 Expression::LocationStep(LocationStepExpression {
767 axis: Axis::Attribute,
768 node_test: NodeTest::Name(QualName {
769 prefix: None,
770 ns: ns!(),
771 local: local_name!("title"),
772 }),
773 predicate_list: PredicateListExpression {
774 predicates: vec![],
775 },
776 }),
777 Expression::Binary(
778 Box::new(Expression::LocationStep(
779 LocationStepExpression {
780 axis: Axis::Attribute,
781 node_test: NodeTest::Name(QualName {
782 prefix: Some(namespace_prefix!("xml")),
783 ns: ns!(html),
784 local: local_name!("lang"),
785 }),
786 predicate_list: PredicateListExpression {
787 predicates: vec![],
788 },
789 },
790 )),
791 BinaryOperator::Equal,
792 Box::new(Expression::Literal(Literal::String(
793 "en-GB".to_owned(),
794 ))),
795 ),
796 ],
797 },
798 }),
799 ],
800 }),
801 ),
802 ];
803
804 for (input, expected) in cases {
805 match parse(&mut (), input, Some(DummyNamespaceResolver), true) {
806 Ok(result) => {
807 assert_eq!(result, expected, "{:?} was parsed incorrectly", input);
808 },
809 Err(e) => panic!("Failed to parse '{}': {:?}", input, e),
810 }
811 }
812 }
813
814 #[test]
815 fn parse_expression_in_parenthesis() {
816 let test_case = "(./span)";
817 let expected = Expression::Path(PathExpression {
818 is_absolute: false,
819 has_implicit_descendant_or_self_step: false,
820 steps: vec![
821 Expression::LocationStep(LocationStepExpression {
822 axis: Axis::Self_,
823 node_test: NodeTest::Kind(KindTest::Node),
824 predicate_list: PredicateListExpression { predicates: vec![] },
825 }),
826 Expression::LocationStep(LocationStepExpression {
827 axis: Axis::Child,
828 node_test: NodeTest::Name(QualName {
829 prefix: None,
830 ns: ns!(),
831 local: local_name!("span"),
832 }),
833 predicate_list: PredicateListExpression { predicates: vec![] },
834 }),
835 ],
836 });
837 match parse(&mut (), test_case, Some(DummyNamespaceResolver), true) {
838 Ok(result) => {
839 assert_eq!(result, expected, "{:?} was parsed incorrectly", test_case);
840 },
841 Err(e) => panic!("Failed to parse '{}': {:?}", test_case, e),
842 }
843 }
844}