The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Xslt \ XPathPatternParser

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XPathPatternParser.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System.Collections.Generic;
  16. using System.Diagnostics;
  17. using System.Xml;
  18. using System.Xml.Xsl.Qil;
  19. using System.Xml.Xsl.XPath;
  20. namespace System.Xml.Xsl.Xslt
  21. {
  22.     using XPathParser = XPathParser<QilNode>;
  23.     using XPathNodeType = System.Xml.XPath.XPathNodeType;
  24.     using Res = System.Xml.Utils.Res;
  25.    
  26.     internal class XPathPatternParser
  27.     {
  28.         public interface IPatternBuilder : IXPathBuilder<QilNode>
  29.         {
  30.             IXPathBuilder<QilNode> GetPredicateBuilder(QilNode context);
  31.         }
  32.        
  33.         XPathScanner scanner;
  34.         IPatternBuilder ptrnBuilder;
  35.         XPathParser predicateParser = new XPathParser();
  36.        
  37.         public QilNode Parse(XPathScanner scanner, IPatternBuilder ptrnBuilder)
  38.         {
  39.             Debug.Assert(this.scanner == null && this.ptrnBuilder == null);
  40.             Debug.Assert(scanner != null && ptrnBuilder != null);
  41.             QilNode result = null;
  42.             ptrnBuilder.StartBuild();
  43.             try {
  44.                 this.scanner = scanner;
  45.                 this.ptrnBuilder = ptrnBuilder;
  46.                 result = this.ParsePattern();
  47.                 this.scanner.CheckToken(LexKind.Eof);
  48.             }
  49.             finally {
  50.                 result = ptrnBuilder.EndBuild(result);
  51.                 #if DEBUG
  52.                 this.ptrnBuilder = null;
  53.                 this.scanner = null;
  54.                 #endif
  55.             }
  56.             return result;
  57.         }
  58.        
  59. /*
  60.         *  Pattern ::= LocationPathPattern ('|' LocationPathPattern)*
  61.         */       
  62.         private QilNode ParsePattern()
  63.         {
  64.             QilNode opnd = ParseLocationPathPattern();
  65.            
  66.             while (scanner.Kind == LexKind.Union) {
  67.                 scanner.NextLex();
  68.                 opnd = ptrnBuilder.Operator(XPathOperator.Union, opnd, ParseLocationPathPattern());
  69.             }
  70.             return opnd;
  71.         }
  72.        
  73. /*
  74.         *  LocationPathPattern ::= '/' RelativePathPattern? | '//'? RelativePathPattern | IdKeyPattern (('/' | '//') RelativePathPattern)?
  75.         */       
  76.         private QilNode ParseLocationPathPattern()
  77.         {
  78.             QilNode opnd;
  79.            
  80.             switch (scanner.Kind) {
  81.                 case LexKind.Slash:
  82.                     scanner.NextLex();
  83.                     opnd = ptrnBuilder.Axis(XPathAxis.Root, XPathNodeType.All, null, null);
  84.                    
  85.                     if (XPathParser.IsStep(scanner.Kind)) {
  86.                         opnd = ptrnBuilder.JoinStep(opnd, ParseRelativePathPattern());
  87.                     }
  88.                     return opnd;
  89.                 case LexKind.SlashSlash:
  90.                     scanner.NextLex();
  91.                     return ptrnBuilder.JoinStep(ptrnBuilder.Axis(XPathAxis.Root, XPathNodeType.All, null, null), ptrnBuilder.JoinStep(ptrnBuilder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null), ParseRelativePathPattern()));
  92.                 case LexKind.Name:
  93.                     if (scanner.CanBeFunction && scanner.Prefix.Length == 0 && (scanner.Name == "id" || scanner.Name == "key")) {
  94.                         opnd = ParseIdKeyPattern();
  95.                         switch (scanner.Kind) {
  96.                             case LexKind.Slash:
  97.                                 scanner.NextLex();
  98.                                 opnd = ptrnBuilder.JoinStep(opnd, ParseRelativePathPattern());
  99.                                 break;
  100.                             case LexKind.SlashSlash:
  101.                                 scanner.NextLex();
  102.                                 opnd = ptrnBuilder.JoinStep(opnd, ptrnBuilder.JoinStep(ptrnBuilder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null), ParseRelativePathPattern()));
  103.                                 break;
  104.                         }
  105.                         return opnd;
  106.                     }
  107.                     break;
  108.             }
  109.             opnd = ParseRelativePathPattern();
  110.             return opnd;
  111.         }
  112.        
  113. /*
  114.         *  IdKeyPattern ::= 'id' '(' Literal ')' | 'key' '(' Literal ',' Literal ')'
  115.         */       
  116.         private QilNode ParseIdKeyPattern()
  117.         {
  118.             Debug.Assert(scanner.CanBeFunction);
  119.             Debug.Assert(scanner.Prefix.Length == 0);
  120.             Debug.Assert(scanner.Name == "id" || scanner.Name == "key");
  121.             List<QilNode> args = new List<QilNode>(2);
  122.            
  123.             if (scanner.Name == "id") {
  124.                 scanner.NextLex();
  125.                 scanner.PassToken(LexKind.LParens);
  126.                 scanner.CheckToken(LexKind.String);
  127.                 args.Add(ptrnBuilder.String(scanner.StringValue));
  128.                 scanner.NextLex();
  129.                 scanner.PassToken(LexKind.RParens);
  130.                 return ptrnBuilder.Function("", "id", args);
  131.             }
  132.             else {
  133.                 scanner.NextLex();
  134.                 scanner.PassToken(LexKind.LParens);
  135.                 scanner.CheckToken(LexKind.String);
  136.                 args.Add(ptrnBuilder.String(scanner.StringValue));
  137.                 scanner.NextLex();
  138.                 scanner.PassToken(LexKind.Comma);
  139.                 scanner.CheckToken(LexKind.String);
  140.                 args.Add(ptrnBuilder.String(scanner.StringValue));
  141.                 scanner.NextLex();
  142.                 scanner.PassToken(LexKind.RParens);
  143.                 return ptrnBuilder.Function("", "key", args);
  144.             }
  145.         }
  146.        
  147. /*
  148.         *  RelativePathPattern ::= StepPattern (('/' | '//') StepPattern)*
  149.         */       
  150.         private QilNode ParseRelativePathPattern()
  151.         {
  152.             QilNode opnd = ParseStepPattern();
  153.             if (scanner.Kind == LexKind.Slash) {
  154.                 scanner.NextLex();
  155.                 opnd = ptrnBuilder.JoinStep(opnd, ParseRelativePathPattern());
  156.             }
  157.             else if (scanner.Kind == LexKind.SlashSlash) {
  158.                 scanner.NextLex();
  159.                 opnd = ptrnBuilder.JoinStep(opnd, ptrnBuilder.JoinStep(ptrnBuilder.Axis(XPathAxis.DescendantOrSelf, XPathNodeType.All, null, null), ParseRelativePathPattern()));
  160.             }
  161.             return opnd;
  162.         }
  163.        
  164. /*
  165.         *  StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
  166.         *  ChildOrAttributeAxisSpecifier ::= @ ? | ('child' | 'attribute') '::'
  167.         */       
  168.         private QilNode ParseStepPattern()
  169.         {
  170.             QilNode opnd;
  171.             XPathAxis axis;
  172.            
  173.             switch (scanner.Kind) {
  174.                 case LexKind.Dot:
  175.                 case LexKind.DotDot:
  176.                     throw scanner.CreateException(Res.XPath_InvalidAxisInPattern);
  177.                     break;
  178.                 case LexKind.At:
  179.                     //>> '@'
  180.                     axis = XPathAxis.Attribute;
  181.                     scanner.NextLex();
  182.                     break;
  183.                 case LexKind.Axis:
  184.                     //>> AxisName '::'
  185.                     axis = XPathParser.GetAxis(scanner.Name, scanner);
  186.                     if (axis != XPathAxis.Child && axis != XPathAxis.Attribute) {
  187.                         throw scanner.CreateException(Res.XPath_InvalidAxisInPattern);
  188.                     }
  189.                     scanner.NextLex();
  190.                     break;
  191.                 case LexKind.Name:
  192.                 case LexKind.Star:
  193.                     // NodeTest must start with Name or '*'
  194.                     axis = XPathAxis.Child;
  195.                     break;
  196.                 default:
  197.                     throw scanner.CreateException(Res.XPath_UnexpectedToken, scanner.RawValue);
  198.                     break;
  199.             }
  200.            
  201.             XPathNodeType nodeType;
  202.             string nodePrefix;
  203.             string nodeName;
  204.             XPathParser.InternalParseNodeTest(scanner, axis, out nodeType, out nodePrefix, out nodeName);
  205.             opnd = ptrnBuilder.Axis(axis, nodeType, nodePrefix, nodeName);
  206.            
  207.             while (scanner.Kind == LexKind.LBracket) {
  208.                     /*reverseStep:*/                opnd = ptrnBuilder.Predicate(opnd, ParsePredicate(opnd), false);
  209.             }
  210.             return opnd;
  211.         }
  212.        
  213. /*
  214.         *  Predicate ::= '[' Expr ']'
  215.         */       
  216.         private QilNode ParsePredicate(QilNode context)
  217.         {
  218.             Debug.Assert(scanner.Kind == LexKind.LBracket);
  219.             scanner.NextLex();
  220.             QilNode result = predicateParser.Parse(scanner, ptrnBuilder.GetPredicateBuilder(context), LexKind.RBracket);
  221.             Debug.Assert(scanner.Kind == LexKind.RBracket);
  222.             scanner.NextLex();
  223.             return result;
  224.         }
  225.     }
  226. }

Developer Fusion