Hi,
I wonder which is the best way to have "almost duplicate" but
different parser/tokenizer pair for XSLT "Pattern" apart from
XPath (I'm going to fix a bug that allows improper XPath for
XSLT pattern e.g. namespace::*).
With my way to do, they could be generated by attached patches:
$ patch -i pattern-parser.diff System.Xml.XPath/Parser.jay -o
System.Xml.XPath/PatternParser.jay
$ patch -i pattern-parser.diff System.Xml.XPath/Tokenizer.cs -o
System.Xml.XPath/PatternTokenizer.cs
$ patch -i use-pattern-parser.diff
... but I wonder if there are better ways to do handle those
parser/tokenizer stuff, because parser/tokenizer patches are easy
to become broken when we fix XPath parser and/or tokenizer sources.
Would it be better if I just put another parser/tokenizer pair?
Atsushi Eno--- System.Xml.XPath/Parser.jay 2005-03-17 06:18:09.720068800 +0900
+++ System.Xml.XPath/PatternParser.jay 2005-03-17 06:15:04.253380800 +0900
@@ -1,7 +1,9 @@
%{
-// XPath parser
+// XSLT Pattern parser
//
-// Author - Piers Haken <[EMAIL PROTECTED]>
+// Author: Atsushi Enomoto <[EMAIL PROTECTED]>
+//
+// mostly copied from XPath Parser.jay by Piers Haken <[EMAIL PROTECTED]>
//
using System;
@@ -9,15 +11,15 @@
using System.Xml;
using System.Xml.XPath;
-namespace Mono.Xml.XPath
+namespace System.Xml.Xsl
{
- internal class XPathParser
+ internal class XsltPatternParser
{
internal System.Xml.Xsl.IStaticXsltContext Context;
- public XPathParser () : this (null) {}
- internal XPathParser (System.Xml.Xsl.IStaticXsltContext context)
+ public XsltPatternParser () : this (null) {}
+ internal XsltPatternParser (System.Xml.Xsl.IStaticXsltContext
context)
{
Context = context;
ErrorOutput = System.IO.TextWriter.Null;
@@ -27,12 +29,12 @@
internal Expression Compile (string xpath)
{
try {
- Tokenizer tokenizer = new Tokenizer (xpath);
+ PatternTokenizer tokenizer = new
PatternTokenizer (xpath);
return (Expression) yyparse (tokenizer);
} catch (XPathException e) {
throw;
- } catch (Exception e) {
- throw new XPathException ("Error during parse
of " + xpath, e);
+// } catch (Exception e) {
+// throw new XPathException ("Error during parse
of " + xpath, e);
}
}
static int yacc_verbose_flag;
@@ -125,7 +127,7 @@
%token QName
-%start Expr
+%start Pattern
%left AND
@@ -144,6 +146,115 @@
%%
+/* 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
--- System.Xml.XPath/Tokenizer.cs 2005-03-17 05:06:04.510723200 +0900
+++ System.Xml.XPath/PatternTokenizer.cs 2005-03-17 05:40:17.192334400
+0900
@@ -32,12 +32,12 @@
using System.IO;
using System.Text;
using System.Collections;
+using System.Xml.XPath;
using Mono.Xml.XPath;
-using Mono.Xml.XPath.yyParser;
-namespace System.Xml.XPath
+namespace System.Xml.Xsl
{
- internal class Tokenizer : Mono.Xml.XPath.yyParser.yyInput
+ internal class PatternTokenizer : yyParser.yyInput
{
private string m_rgchInput;
private int m_ich;
@@ -74,13 +74,13 @@
};
private const char EOL = '\0';
- static Tokenizer ()
+ static PatternTokenizer ()
{
for (int i = 0; i < s_rgTokenMap.Length; i += 2)
s_mapTokens.Add (s_rgTokenMap [i + 1],
s_rgTokenMap [i]);
}
- public Tokenizer (string strInput)
+ public PatternTokenizer (string strInput)
{
//Console.WriteLine ("Tokenizing: " + strInput);
m_rgchInput = strInput;
Index: Makefile
===================================================================
--- Makefile (revision 41902)
+++ Makefile (working copy)
@@ -40,6 +40,7 @@
$(wildcard System.Xml.Serialization/standalone_tests/*.cs) \
$(wildcard System.Xml.Serialization/standalone_tests/*.output) \
System.Xml.XPath/Parser.jay \
+ System.Xml.XPath/PatternParser.jay \
System.Xml.Query/XQueryParser.jay \
System.Xml.Query/skeleton-2.0.cs \
Test/Microsoft.Test.csproj \
@@ -54,10 +55,15 @@
System.Xml.XPath/Parser.cs: System.Xml.XPath/Parser.jay
$(topdir)/jay/skeleton.cs
$(topdir)/jay/jay -ct < $(topdir)/jay/skeleton.cs $< >$@
+System.Xml.XPath/PatternParser.cs: System.Xml.XPath/PatternParser.jay
$(topdir)/jay/skeleton.cs
+ $(topdir)/jay/jay -ct < $(topdir)/jay/skeleton.cs $< >$@
+
System.Xml.Query/XQueryParser.cs: System.Xml.Query/XQueryParser.jay
System.Xml.Query/skeleton-2.0.cs
$(topdir)/jay/jay -ct < System.Xml.Query/skeleton-2.0.cs $< >$@
-BUILT_SOURCES = System.Xml.XPath/Parser.cs #System.Xml.Query/XQueryParser.cs
+BUILT_SOURCES = System.Xml.XPath/Parser.cs \
+ System.Xml.XPath/PatternParser.cs
+ #System.Xml.Query/XQueryParser.cs
CLEAN_FILES = Test/XmlFiles/xsl/result.xml System.Xml.Query/XQueryParser.cs
include ../../build/library.make
Index: Mono.Xml.XPath/Pattern.cs
===================================================================
--- Mono.Xml.XPath/Pattern.cs (revision 41902)
+++ Mono.Xml.XPath/Pattern.cs (working copy)
@@ -43,7 +43,7 @@
{
internal static Pattern Compile (string s, Compiler comp)
{
- return Compile (comp.parser.Compile (s));
+ return Compile (comp.patternParser.Compile (s));
}
internal static Pattern Compile (Expression e)
Index: Mono.Xml.Xsl/Compiler.cs
===================================================================
--- Mono.Xml.Xsl/Compiler.cs (revision 41902)
+++ Mono.Xml.Xsl/Compiler.cs (working copy)
@@ -127,7 +127,8 @@
public CompiledStylesheet Compile (XPathNavigator nav,
XmlResolver res, Evidence evidence)
{
- this.parser = new XPathParser (this);
+ this.xpathParser = new XPathParser (this);
+ this.patternParser = new XsltPatternParser (this);
this.res = res;
if (res == null)
this.res = new XmlUrlResolver ();
@@ -350,7 +351,8 @@
return p;
}
- internal XPathParser parser;
+ internal XPathParser xpathParser;
+ internal XsltPatternParser patternParser;
internal CompiledExpression CompileExpression (string
expression)
{
return CompileExpression (expression, false);
@@ -360,7 +362,7 @@
{
if (expression == null || expression == "") return null;
- Expression expr = parser.Compile (expression);
+ Expression expr = xpathParser.Compile (expression);
if (isKey)
expr = new ExprKeyContainer (expr);
CompiledExpression e = new CompiledExpression
(expression, expr);