| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- //
- // System.Xml.XPath.XPathScanner
- //
- // Author:
- // Jason Diamond ([email protected])
- //
- // (C) 2002 Jason Diamond http://injektilo.org/
- //
- using System;
- using System.IO;
- using System.Text;
- // [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
- // | NameTest
- // | NodeType
- // | Operator
- // | FunctionName
- // | AxisName
- // | Literal
- // | Number
- // | VariableReference
- // [29] Literal ::= '"' [^"]* '"'
- // | "'" [^']* "'"
- // [30] Number ::= Digits ('.' Digits?)?
- // | '.' Digits
- // [31] Digits ::= [0-9]+
- // [32] Operator ::= OperatorName
- // | MultiplyOperator
- // | '/' | '//' | '|' | '+' | '-' | '=' | '!=' | '<' | '<=' | '>' | '>='
- // [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
- // [34] MultiplyOperator ::= '*'
- // [35] FunctionName ::= QName - NodeType
- // [36] VariableReference ::= '$' QName
- // [37] NameTest ::= '*'
- // | NCName ':' '*'
- // | QName
- // [38] NodeType ::= 'comment'
- // | 'text'
- // | 'processing-instruction'
- // | 'node'
- // [39] ExprWhitespace ::= S
- namespace System.Xml.XPath
- {
- public enum XPathTokenType
- {
- Start,
- End,
- Error,
- LeftParen,
- RightParen,
- LeftBracket,
- RightBracket,
- Dot,
- DotDot,
- At,
- Comma,
- ColonColon,
- NameTest,
- NodeType,
- Operator,
- FunctionName,
- AxisName,
- Literal,
- Number,
- VariableReference
- }
- public class XPathScanner
- {
- private string xpath;
- private int index;
- private XPathTokenType tokenType;
- private string value;
- private XPathTokenType precedingTokenType;
- public XPathScanner (string xpath)
- {
- this.xpath = xpath;
- index = 0;
- tokenType = XPathTokenType.Start;
- }
- public XPathTokenType TokenType {
- get {
- return tokenType;
- }
- }
- public string Value {
- get {
- return value;
- }
- }
- private int Read ()
- {
- int c = Peek ();
- if (c != -1)
- MoveNext ();
- return c;
- }
- private int Peek ()
- {
- if (index < xpath.Length)
- return xpath[index];
- return -1;
- }
- private int Peek2 ()
- {
- if (index + 1 < xpath.Length)
- return xpath[index + 1];
- return -1;
- }
- private void MoveNext ()
- {
- ++index;
- }
- private void MovePrevious ()
- {
- if (index > 0)
- --index;
- }
- public XPathTokenType Scan ()
- {
- precedingTokenType = tokenType;
- int c = Read ();
- if (c == -1) {
- tokenType = XPathTokenType.End;
- value = null;
- } else if (c != ':' && XmlChar.IsFirstNameChar (c)) {
- StringBuilder builder = new StringBuilder ();
- builder.Append ((char) c);
- while (Peek () != ':' && XmlChar.IsNameChar (Peek ())) {
- builder.Append ((char) Read ());
- }
- if (Peek () == ':' && Peek2 () != ':') {
- Read();
- if (XmlChar.IsFirstNameChar (Peek ())) {
- builder.Append (':');
- builder.Append ((char) Read ());
- while (XmlChar.IsNameChar (Peek ())) {
- builder.Append ((char) Read ());
- }
- tokenType = XPathTokenType.NameTest;
- } else if (Peek () == '*') {
- builder.Append (':');
- builder.Append ((char) Read ());
- tokenType = XPathTokenType.NameTest;
- value = builder.ToString ();
- return tokenType;
- } else {
- tokenType = XPathTokenType.Error;
- return tokenType;
- }
- }
- value = builder.ToString ();
- if (precedingTokenType != XPathTokenType.Start &&
- precedingTokenType != XPathTokenType.At &&
- precedingTokenType != XPathTokenType.ColonColon &&
- precedingTokenType != XPathTokenType.LeftParen &&
- precedingTokenType != XPathTokenType.LeftBracket &&
- precedingTokenType != XPathTokenType.Operator)
- tokenType = XPathTokenType.Operator;
- else if (Peek () == '(') {
- if (value == "comment" ||
- value == "node" ||
- value == "processing-instruction" ||
- value == "text")
- tokenType = XPathTokenType.NodeType;
- else
- tokenType = XPathTokenType.FunctionName;
- } else {
- if (Peek () == ':' && Peek2 () == ':')
- tokenType = XPathTokenType.AxisName;
- else
- tokenType = XPathTokenType.NameTest;
- }
- value = builder.ToString ();
- } else {
- switch (c) {
- case '(':
- tokenType = XPathTokenType.LeftParen;
- value = "(";
- break;
- case ')':
- tokenType = XPathTokenType.RightParen;
- value = ")";
- break;
- case '[':
- tokenType = XPathTokenType.LeftBracket;
- break;
- case ']':
- tokenType = XPathTokenType.RightBracket;
- break;
- case '.':
- if (Peek () != '.') {
- tokenType = XPathTokenType.Dot;
- value = ".";
- } else {
- Read ();
- tokenType = XPathTokenType.DotDot;
- value = "..";
- }
- break;
- case '@':
- tokenType = XPathTokenType.At;
- value = "@";
- break;
- case ',':
- tokenType = XPathTokenType.Comma;
- break;
- case ':':
- if (Peek () == ':') {
- Read ();
- tokenType = XPathTokenType.ColonColon;
- value = "::";
- } else
- tokenType = XPathTokenType.Error;
- break;
- case '*':
- if (precedingTokenType != XPathTokenType.Start &&
- precedingTokenType != XPathTokenType.At &&
- precedingTokenType != XPathTokenType.ColonColon &&
- precedingTokenType != XPathTokenType.LeftParen &&
- precedingTokenType != XPathTokenType.LeftBracket &&
- precedingTokenType != XPathTokenType.Operator) {
- tokenType = XPathTokenType.Operator;
- value = "*";
- } else {
- tokenType = XPathTokenType.NameTest;
- value = "*";
- }
- break;
- default:
- if (c == '/') {
- tokenType = XPathTokenType.Operator;
- if (Peek () != '/')
- value = "/";
- else {
- Read ();
- value = "//";
- }
- }
- break;
- }
- }
- return tokenType;
- }
- }
- }
|