2 /* XPathParser.y - An XPath 1.0 parser.
3 Copyright (C) 2004 The Free Software Foundation
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package gnu.xml.xpath
;
42 import java.util.ArrayList
;
43 import java.util.Collections
;
44 import java.util.List
;
46 import javax.xml.namespace.NamespaceContext
;
47 import javax.xml.namespace.QName
;
48 import javax.xml.xpath.XPathFunctionResolver
;
49 import javax.xml.xpath.XPathVariableResolver
;
50 import org.w3c.dom.Node
;
53 * An XPath 1.0 parser.
55 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
57 public class XPathParser
60 NamespaceContext namespaceContext
;
61 XPathVariableResolver variableResolver
;
62 XPathFunctionResolver functionResolver
;
64 QName getQName
(String name
)
66 QName qName
= QName.valueOf
(name
);
67 if
(namespaceContext
!= null
)
69 String prefix
= qName.getPrefix
();
70 String uri
= qName.getNamespaceURI
();
71 if
(prefix
!= null
&& (uri
== null || uri.length
() == 0))
73 uri
= namespaceContext.getNamespaceURI
(prefix
);
74 String localName
= qName.getLocalPart
();
75 qName
= new QName
(uri
, localName
, prefix
);
81 Expr lookupFunction
(String name
, List
<Expr
> args
)
83 int arity
= args.size
();
84 if
("position".equals
(name
) && arity
== 0)
86 return new PositionFunction
();
88 else if
("last".equals
(name
) && arity
== 0)
90 return new LastFunction
();
92 else if
("string".equals
(name
) && (arity
== 1 || arity
== 0))
94 return new StringFunction
(args
);
96 else if
("number".equals
(name
) && (arity
== 1 || arity
== 0))
98 return new NumberFunction
(args
);
100 else if
("boolean".equals
(name
) && arity
== 1)
102 return new BooleanFunction
(args
);
104 else if
("count".equals
(name
) && arity
== 1)
106 return new CountFunction
(args
);
108 else if
("not".equals
(name
) && arity
== 1)
110 return new NotFunction
(args
);
112 else if
("id".equals
(name
) && arity
== 1)
114 return new IdFunction
(args
);
116 else if
("concat".equals
(name
) && arity
> 1)
118 return new ConcatFunction
(args
);
120 else if
("true".equals
(name
) && arity
== 0)
122 return new TrueFunction
();
124 else if
("false".equals
(name
) && arity
== 0)
126 return new FalseFunction
();
128 else if
("name".equals
(name
) && (arity
== 1 || arity
== 0))
130 return new NameFunction
(args
);
132 else if
("local-name".equals
(name
) && (arity
== 1 || arity
== 0))
134 return new LocalNameFunction
(args
);
136 else if
("namespace-uri".equals
(name
) && (arity
== 1 || arity
== 0))
138 return new NamespaceUriFunction
(args
);
140 else if
("starts-with".equals
(name
) && arity
== 2)
142 return new StartsWithFunction
(args
);
144 else if
("contains".equals
(name
) && arity
== 2)
146 return new ContainsFunction
(args
);
148 else if
("string-length".equals
(name
) && (arity
== 1 || arity
== 0))
150 return new StringLengthFunction
(args
);
152 else if
("translate".equals
(name
) && arity
== 3)
154 return new TranslateFunction
(args
);
156 else if
("normalize-space".equals
(name
) && (arity
== 1 || arity
== 0))
158 return new NormalizeSpaceFunction
(args
);
160 else if
("substring".equals
(name
) && (arity
== 2 || arity
== 3))
162 return new SubstringFunction
(args
);
164 else if
("substring-before".equals
(name
) && arity
== 2)
166 return new SubstringBeforeFunction
(args
);
168 else if
("substring-after".equals
(name
) && arity
== 2)
170 return new SubstringAfterFunction
(args
);
172 else if
("lang".equals
(name
) && arity
== 1)
174 return new LangFunction
(args
);
176 else if
("sum".equals
(name
) && arity
== 1)
178 return new SumFunction
(args
);
180 else if
("floor".equals
(name
) && arity
== 1)
182 return new FloorFunction
(args
);
184 else if
("ceiling".equals
(name
) && arity
== 1)
186 return new CeilingFunction
(args
);
188 else if
("round".equals
(name
) && arity
== 1)
190 return new RoundFunction
(args
);
192 else if
(functionResolver
!= null
)
194 QName qName
= QName.valueOf
(name
);
195 Object function
= functionResolver.resolveFunction
(qName
, arity
);
196 if
(function
!= null
&&
197 function instanceof Function
&&
198 function instanceof Expr
)
200 Function f
= (Function
) function
;
201 f.setArguments
(args
);
202 return
(Expr
) function
;
205 return new FunctionCall
(functionResolver
, name
, args
);
221 %token DOUBLE_SLASH
// '//'
234 %token DOUBLE_COLON
// '::'
236 %token DOUBLE_DOT
// '..'
239 %token ANCESTOR_OR_SELF
243 %token DESCENDANT_OR_SELF
245 %token FOLLOWING_SIBLING
249 %token PRECEDING_SIBLING
256 %token PROCESSING_INSTRUCTION
271 relative_location_path
272 | absolute_location_path
275 absolute_location_path:
280 | SLASH relative_location_path
283 if
($2 instanceof Steps
)
290 steps.path.addFirst
((Expr
) $2);
292 steps.path.addFirst
(new Root
());
294 //$$ = new Step(new Root(), (Path) $2);
296 | DOUBLE_SLASH relative_location_path
298 Test nt
= new NodeTypeTest
((short) 0);
299 Selector s
= new Selector
(Selector.DESCENDANT_OR_SELF
,
300 Collections.singletonList
(nt
));
302 if
($2 instanceof Steps
)
309 steps.path.addFirst
((Expr
) $2);
311 steps.path.addFirst
(s
);
312 steps.path.addFirst
(new Root
());
314 //Step step = new Step(s, (Path) $2);
315 //$$ = new Step(new Root(), step);
319 relative_location_path:
321 | relative_location_path SLASH step
324 if
($1 instanceof Steps
)
331 steps.path.addFirst
((Expr
) $1);
333 steps.path.addLast
((Expr
) $3);
335 //$$ = new Step((Expr) $1, (Path) $3);
337 | relative_location_path DOUBLE_SLASH step
339 Test nt
= new NodeTypeTest
((short) 0);
340 Selector s
= new Selector
(Selector.DESCENDANT_OR_SELF
,
341 Collections.singletonList
(nt
));
343 if
($1 instanceof Steps
)
350 steps.path.addFirst
((Expr
) $1);
352 steps.path.addLast
(s
);
353 steps.path.addLast
((Expr
) $3);
355 //Step step = new Step(s, (Path) $3);
356 //$$ = new Step((Expr) $1, step);
363 @SuppressWarnings
("unchecked") List
<Test
> tests
= (List
<Test
>) $1;
364 $$
= new Selector
(Selector.CHILD
, tests
);
368 @SuppressWarnings
("unchecked") List
<Test
> tests
= (List
<Test
>) $2;
369 $$
= new Selector
(Selector.ATTRIBUTE
, tests
);
371 | axis_name DOUBLE_COLON step_node_test
373 @SuppressWarnings
("unchecked") List
<Test
> tests
= (List
<Test
>) $3;
374 $$
= new Selector
(((Integer
) $1).intValue
(), tests
);
378 List
<Test
> emptyList
= Collections.emptyList
();
379 $$
= new Selector
(Selector.SELF
, emptyList
);
383 List
<Test
> emptyList
= Collections.emptyList
();
384 $$
= new Selector
(Selector.PARENT
, emptyList
);
391 List
<Test
> list
= new ArrayList
<Test
>();
395 | step_node_test predicate
397 /* This is safe as we create this in one of the other cases */
398 @SuppressWarnings
("unchecked") List
<Test
> tests
= (List
<Test
>)$1;
399 tests.add
((Test
) $2);
407 List list = new ArrayList ();
411 | predicate predicate_list
413 List list = (List) $3;
422 $$
= new Integer
(Selector.ANCESTOR
);
426 $$
= new Integer
(Selector.ANCESTOR_OR_SELF
);
430 $$
= new Integer
(Selector.ATTRIBUTE
);
434 $$
= new Integer
(Selector.CHILD
);
438 $$
= new Integer
(Selector.DESCENDANT
);
442 $$
= new Integer
(Selector.DESCENDANT_OR_SELF
);
446 $$
= new Integer
(Selector.FOLLOWING
);
450 $$
= new Integer
(Selector.FOLLOWING_SIBLING
);
454 $$
= new Integer
(Selector.NAMESPACE
);
458 $$
= new Integer
(Selector.PARENT
);
462 $$
= new Integer
(Selector.PRECEDING
);
466 $$
= new Integer
(Selector.PRECEDING_SIBLING
);
470 $$
= new Integer
(Selector.SELF
);
476 /*| PROCESSING_INSTRUCTION LP LITERAL RP*/
477 | PROCESSING_INSTRUCTION LITERAL RP
479 $$
= new NodeTypeTest
(Node.PROCESSING_INSTRUCTION_NODE
, (String
) $2);
481 /*| node_type LP RP*/
484 $$
= new NodeTypeTest
(((Short
) $1).shortValue
());
491 $$
= new Predicate
((Expr
) $2);
499 $$
= new ParenthesizedExpr
((Expr
) $2);
503 $$
= new Constant
($1);
507 $$
= new Constant
($1);
515 List
<Expr
> emptyList
= Collections.emptyList
();
516 $$
= lookupFunction
((String
) $1, emptyList
);
518 | function_name LP argument_list RP
520 /* This is safe as we create this below */
521 @SuppressWarnings
("unchecked") List
<Expr
> exprs
= (List
<Expr
>) $3;
522 $$
= lookupFunction
((String
) $1, (List
) exprs
);
529 List
<Expr
> list
= new ArrayList
<Expr
>();
533 | expr COMMA argument_list
535 /* This is safe as we create this above */
536 @SuppressWarnings
("unchecked") List
<Expr
> list
= (List
<Expr
>) $3;
537 list.add
(0, (Expr
) $1);
544 | union_expr PIPE path_expr
546 $$
= new UnionExpr
((Expr
) $1, (Expr
) $3);
553 | filter_expr SLASH relative_location_path
556 if
($3 instanceof Steps
)
563 steps.path.addFirst
((Expr
) $3);
565 steps.path.addFirst
((Expr
) $1);
567 //$$ = new Step ((Expr) $1, (Path) $3);
569 | filter_expr DOUBLE_SLASH relative_location_path
571 Test nt
= new NodeTypeTest
((short) 0);
572 Selector s
= new Selector
(Selector.DESCENDANT_OR_SELF
,
573 Collections.singletonList
(nt
));
575 if
($3 instanceof Steps
)
582 steps.path.addFirst
($3);
584 steps.path.addFirst
(s
);
585 steps.path.addFirst
((Expr
) $1);
587 //Step step = new Step (s, (Path) $3);
588 //$$ = new Step ((Expr) $1, step);
594 | filter_expr predicate
596 Predicate filter
= (Predicate
) $2;
597 Selector s
= new Selector
(Selector.SELF
,
598 Collections.singletonList
(filter
));
600 if
($1 instanceof Steps
)
607 steps.path.addFirst
((Expr
) $1);
609 steps.path.addLast
(s
);
611 //$$ = new Step ((Expr) $1, s);
617 | or_expr OR and_expr
619 $$
= new OrExpr
((Expr
) $1, (Expr
) $3);
625 | and_expr AND equality_expr
627 $$
= new AndExpr
((Expr
) $1, (Expr
) $3);
633 | equality_expr EQ relational_expr
635 $$
= new EqualityExpr
((Expr
) $1, (Expr
) $3, false
);
637 | equality_expr NE relational_expr
639 $$
= new EqualityExpr
((Expr
) $1, (Expr
) $3, true
);
645 | relational_expr LT additive_expr
647 $$
= new RelationalExpr
((Expr
) $1, (Expr
) $3, true
, false
);
649 | relational_expr GT additive_expr
651 $$
= new RelationalExpr
((Expr
) $1, (Expr
) $3, false
, false
);
653 | relational_expr LTE additive_expr
655 $$
= new RelationalExpr
((Expr
) $1, (Expr
) $3, true
, true
);
657 | relational_expr GTE additive_expr
659 $$
= new RelationalExpr
((Expr
) $1, (Expr
) $3, false
, true
);
665 | additive_expr PLUS multiplicative_expr
667 $$
= new ArithmeticExpr
((Expr
) $1, (Expr
) $3, ArithmeticExpr.ADD
);
669 | additive_expr MINUS multiplicative_expr
671 $$
= new ArithmeticExpr
((Expr
) $1, (Expr
) $3, ArithmeticExpr.SUBTRACT
);
677 | multiplicative_expr STAR unary_expr
679 $$
= new ArithmeticExpr
((Expr
) $1, (Expr
) $3, ArithmeticExpr.MULTIPLY
);
681 | multiplicative_expr DIV unary_expr
683 $$
= new ArithmeticExpr
((Expr
) $1, (Expr
) $3, ArithmeticExpr.DIVIDE
);
685 | multiplicative_expr MOD unary_expr
687 $$
= new ArithmeticExpr
((Expr
) $1, (Expr
) $3, ArithmeticExpr.MODULO
);
693 | MINUS unary_expr %prec UNARY
695 $$
= new NegativeExpr
((Expr
) $2);
702 $$
= new Double
((String
) $1 + ".0");
706 $$
= new Double
((String
) $1 + ".0");
710 $$
= new Double
((String
) $1 + "." + (String
) $3);
714 $$
= new Double
("0." + (String
) $2);
722 switch (((Short) $1).shortValue ())
724 case Node.COMMENT_NODE:
730 case Node.PROCESSING_INSTRUCTION_NODE:
731 $$ = "processing-instruction";
743 String name
= (String
) $2;
744 $$
= new VariableReference
(variableResolver
, getQName
(name
));
751 $$
= new NameTest
(null
, true
, true
);
755 QName qName
= getQName
((String
) $1);
756 $$
= new NameTest
(qName
, true
, false
);
760 QName qName
= getQName
((String
) $1);
761 $$
= new NameTest
(qName
, false
, false
);
769 $$
= (String
) $1 + ':' + (String
) $3;
776 $$
= new Short
(Node.COMMENT_NODE
);
780 $$
= new Short
(Node.TEXT_NODE
);
782 | PROCESSING_INSTRUCTION
784 $$
= new Short
(Node.PROCESSING_INSTRUCTION_NODE
);
788 $$
= new Short
((short) 0);