%{
-// XPath parser
+// XPath/XSLT Pattern parser
//
-// Author - Piers Haken <piersh@friskit.com>
+// Author: Piers Haken <piersh@friskit.com>
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// IMPORTANT:
+// Do not edit "PatternParser.jay". It is autogenerated from
+// Parser.jay. It will be overwritten!
//
using System;
+using System.Collections;
using System.Xml;
using System.Xml.XPath;
+#if XSLT_PATTERN
+namespace Mono.Xml.Xsl
+#else
namespace Mono.Xml.XPath
+#endif
{
+#if XSLT_PATTERN
+ internal class XsltPatternParser
+#else
internal class XPathParser
+#endif
{
internal System.Xml.Xsl.IStaticXsltContext Context;
+#if XSLT_PATTERN
+ public XsltPatternParser () : this (null) {}
+ internal XsltPatternParser (System.Xml.Xsl.IStaticXsltContext context)
+#else
public XPathParser () : this (null) {}
internal XPathParser (System.Xml.Xsl.IStaticXsltContext context)
+#endif
{
Context = context;
ErrorOutput = System.IO.TextWriter.Null;
+// debug = new yydebug.yyDebugSimple ();
}
internal Expression Compile (string xpath)
try {
Tokenizer tokenizer = new Tokenizer (xpath);
return (Expression) yyparse (tokenizer);
- } catch (XPathException e) {
- throw e;
+ } catch (XPathException) {
+ throw;
} catch (Exception e) {
throw new XPathException ("Error during parse of " + xpath, e);
}
}
static int yacc_verbose_flag;
+
+ private NodeSet CreateNodeTest (Axes axis, object nodeTest, ArrayList plist)
+ {
+ NodeSet test = CreateNodeTest (axis, nodeTest);
+ if (plist != null) {
+ for (int i = 0; i < plist.Count; i++)
+ test = new ExprFilter (test,
+ (Expression) plist [i]);
+ }
+ return test;
+ }
+
+ private NodeTest CreateNodeTest (Axes axis, object test)
+ {
+ if (test is XPathNodeType)
+ return new NodeTypeTest (axis,
+ (XPathNodeType) test, null);
+ else if (test is string || test == null)
+ return new NodeTypeTest (axis,
+ XPathNodeType.ProcessingInstruction,
+ (string) test);
+ XmlQualifiedName q = (XmlQualifiedName) test;
+ if (q == XmlQualifiedName.Empty)
+ return new NodeTypeTest (axis);
+ else
+ return new NodeNameTest (axis, q, Context);
+ }
%}
%token ERROR
%%
+/* XSLT Pattern */
+
+Pattern
+ : LocationPathPattern
+ | Pattern BAR LocationPathPattern
+ {
+ $$ = new ExprUNION ((NodeSet) $1, (NodeSet) $3);
+ }
+ ;
+
+LocationPathPattern
+ : SLASH
+ {
+ $$ = new ExprRoot ();
+ }
+ | SLASH RelativePathPattern
+ {
+ $$ = new ExprSLASH (new ExprRoot (), (NodeSet) $2);
+ }
+ | IdKeyPattern
+ | IdKeyPattern SLASH RelativePathPattern
+ {
+ $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
+ }
+ | IdKeyPattern SLASH2 RelativePathPattern
+ {
+ $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3);
+ }
+ | SLASH2 RelativePathPattern
+ {
+ $$ = new ExprSLASH2 (new ExprRoot (), (NodeSet) $2);
+ }
+ | RelativePathPattern
+ ;
+
+// to avoid context-sensitive tokenizer, I just reuse FUNCTION_NAME
+IdKeyPattern
+ : FUNCTION_NAME PAREN_OPEN LITERAL PAREN_CLOSE
+ {
+ XmlQualifiedName name = (XmlQualifiedName) $1;
+ if (name.Name != "id" || name.Namespace != String.Empty)
+ throw new XPathException (String.Format ("Expected 'id' but got '{0}'", name));
+ $$ = ExprFunctionCall.Factory (name,
+ new FunctionArguments (
+ new ExprLiteral ((string) $3),
+ null),
+ Context);
+ }
+ | FUNCTION_NAME PAREN_OPEN LITERAL COMMA LITERAL PAREN_CLOSE
+ {
+ XmlQualifiedName name = (XmlQualifiedName) $1;
+ if (name.Name != "key" || name.Namespace != String.Empty)
+ throw new XPathException (String.Format ("Expected 'key' but got '{0}'", name));
+ $$ = Context.TryGetFunction (name,
+ new FunctionArguments (
+ new ExprLiteral ((string) $3),
+ new FunctionArguments (
+ new ExprLiteral ((string) $5),
+ null)));
+ }
+ ;
+
+RelativePathPattern
+ : StepPattern
+ | RelativePathPattern SLASH StepPattern
+ {
+ $$ = new ExprSLASH ((Expression) $1, (NodeSet) $3);
+ }
+ | RelativePathPattern SLASH2 StepPattern
+ {
+ $$ = new ExprSLASH2 ((Expression) $1, (NodeSet) $3);
+ }
+ ;
+
+StepPattern
+ : ChildOrAttributeAxisSpecifier NodeTest Predicates
+ {
+ $$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3);
+ }
+ ;
+
+ChildOrAttributeAxisSpecifier
+ : AbbreviatedAxisSpecifier
+ | CHILD COLON2
+ {
+ $$ = Axes.Child;
+ }
+ | ATTRIBUTE COLON2
+ {
+ $$ = Axes.Attribute;
+ }
+ ;
+
+Predicates
+ : // empty
+ {
+ $$ = null;
+ }
+ | Predicates Predicate
+ {
+ ArrayList al = (ArrayList) $1;
+ if (al == null)
+ al = new ArrayList ();
+ al.Add ((Expression) $2);
+ $$ = al;
+ }
+ ;
+
+/* ---- end of XSLT Pattern ---- */
+
Expr
: OrExpr
;
Step
- : PredicatedStep
- | DOT
+ : AxisSpecifier NodeTest Predicates
{
- $$ = new NodeTypeTest (Axes.Self, XPathNodeType.All);
+ $$ = CreateNodeTest ((Axes) $1, $2, (ArrayList) $3);
}
- | DOT2
+ | AbbreviatedStep
+ ;
+
+NodeTest // QName, XPathNodeType or string
+ : NameTest
+ | NodeType PAREN_OPEN PAREN_CLOSE
{
- $$ = new NodeTypeTest (Axes.Parent, XPathNodeType.All);
+ $$ = (XPathNodeType) $1;
+ }
+ | PROCESSING_INSTRUCTION PAREN_OPEN OptionalLiteral PAREN_CLOSE
+ {
+ $$ = (string) $3;
}
;
-PredicatedStep
- : AxisTest
- | PredicatedStep Predicate
+NameTest
+ : ASTERISK
{
- $$ = new ExprFilter ((NodeSet) $1, (Expression) $2);
+ $$ = XmlQualifiedName.Empty;
}
+ | QName // token QName also contains "blah:*"
;
-AxisTest
- : AxisSpecifier QName
+AbbreviatedStep
+ : DOT
{
- $$ = new NodeNameTest ((Axes) $1, (XmlQualifiedName) $2, Context);
+ $$ = new NodeTypeTest (Axes.Self, XPathNodeType.All);
}
- | AxisSpecifier ASTERISK
+ | DOT2
{
- $$ = new NodeTypeTest ((Axes) $1);
+ $$ = new NodeTypeTest (Axes.Parent, XPathNodeType.All);
}
- | AxisSpecifier NodeType PAREN_OPEN OptionalLiteral PAREN_CLOSE
+ ;
+
+Predicates
+ : /* empty */
{
- $$ = new NodeTypeTest ((Axes) $1, (XPathNodeType) $2, (String) $4);
+ $$ = null;
+ }
+ | Predicates Predicate
+ {
+ ArrayList al = (ArrayList) $1;
+ if (al == null)
+ al = new ArrayList ();
+ al.Add ($2);
+ $$ = al;
}
;
AxisSpecifier
+ : AxisName COLON2
+ {
+ $$ = $1;
+ }
+ | AbbreviatedAxisSpecifier
+ ;
+
+AbbreviatedAxisSpecifier
: /* empty */
{
$$ = Axes.Child;
{
$$ = Axes.Attribute;
}
- | AxisName COLON2
- {
- $$ = $1;
- }
;
NodeType