Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Xml / System / Xml / XPath / Internal / querybuilder.cs / 1 / querybuilder.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- namespace MS.Internal.Xml.XPath { using System; using System.Xml; using System.Xml.XPath; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using FT = Function.FunctionType; internal sealed class QueryBuilder { // Note: Up->Doun, Down->Up: // For operators order is normal: 1 + 2 --> Operator+(1, 2) // For pathes order is reversed: a/b -> ChildQuery_B(input: ChildQuery_A(input: ContextQuery())) // Input flags. We pass them Up->Down. // Using them upper query set states wich controls how inner query will be built. enum Flags { None = 0x00, SmartDesc = 0x01, PosFilter = 0x02, // Node has this flag set when it has position predicate applied to it Filter = 0x04, // Subtree we compiling will be filtered. i.e. Flag not set on rightmost filter. } // Output props. We return them Down->Up. // These are properties of Query tree we have built already. // These properties are closely related to QueryProps exposed by Query node itself. // They have the following difference: // QueryProps describe property of node they are (belong like Reverse) // these Props describe acumulated properties of the tree (like nonFlat) enum Props { None = 0x00, PosFilter = 0x01, // This filter or inner filter was positional: foo[1] or foo[1][true()] HasPosition = 0x02, // Expression may ask position() of the context HasLast = 0x04, // Expression may ask last() of the context NonFlat = 0x08, // Some nodes may be descendent of otheres } // comment are aproximate. This is my best understanding: private string query; private bool allowVar; private bool allowKey; private bool allowCurrent; private bool needContext; private BaseAxisQuery firstInput; // Input of the leftmost predicate. Set by leftmost predicate, used in rightmost one private void Reset() { needContext = false; } private Query ProcessAxis(Axis root, Flags flags, out Props props) { Query result = null; if (root.Prefix.Length > 0) { needContext = true; } firstInput = null; Query qyInput; { if (root.Input != null) { Flags inputFlags = Flags.None; if ((flags & Flags.PosFilter) == 0) { Axis input = root.Input as Axis; if (input != null) { if ( root.TypeOfAxis == Axis.AxisType.Child && input.TypeOfAxis == Axis.AxisType.DescendantOrSelf && input.NodeType == XPathNodeType.All ) { Query qyGrandInput; if (input.Input != null) { qyGrandInput = ProcessNode(input.Input, Flags.SmartDesc, out props); } else { qyGrandInput = new ContextQuery(); props = Props.None; } result = new DescendantQuery(qyGrandInput, root.Name, root.Prefix, root.NodeType, false, input.AbbrAxis); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } props |= Props.NonFlat; return result; } } if (root.TypeOfAxis == Axis.AxisType.Descendant || root.TypeOfAxis == Axis.AxisType.DescendantOrSelf) { inputFlags |= Flags.SmartDesc; } } qyInput = ProcessNode(root.Input, inputFlags, out props); } else { qyInput = new ContextQuery(); props = Props.None; } } switch (root.TypeOfAxis) { case Axis.AxisType.Ancestor: result = new XPathAncestorQuery(qyInput , root.Name, root.Prefix, root.NodeType, false); props |= Props.NonFlat; break; case Axis.AxisType.AncestorOrSelf: result = new XPathAncestorQuery(qyInput, root.Name, root.Prefix, root.NodeType, true); props |= Props.NonFlat; break; case Axis.AxisType.Child: if ((props & Props.NonFlat) != 0) { result = new CacheChildrenQuery(qyInput, root.Name, root.Prefix, root.NodeType); } else { result = new ChildrenQuery(qyInput, root.Name, root.Prefix, root.NodeType); } break; case Axis.AxisType.Parent: result = new ParentQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Descendant: if ((flags & Flags.SmartDesc) != 0) { result = new DescendantOverDescendantQuery(qyInput, false, root.Name, root.Prefix, root.NodeType, /*abbrAxis:*/false); } else { result = new DescendantQuery(qyInput, root.Name, root.Prefix, root.NodeType, false, /*abbrAxis:*/false); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } } props |= Props.NonFlat; break; case Axis.AxisType.DescendantOrSelf: if ((flags & Flags.SmartDesc) != 0) { result = new DescendantOverDescendantQuery(qyInput, true, root.Name, root.Prefix, root.NodeType, root.AbbrAxis); } else { result = new DescendantQuery(qyInput, root.Name, root.Prefix, root.NodeType, true, root.AbbrAxis); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } } props |= Props.NonFlat; break; case Axis.AxisType.Preceding: result = new PrecedingQuery(qyInput, root.Name, root.Prefix, root.NodeType); props |= Props.NonFlat; break; case Axis.AxisType.Following: result = new FollowingQuery(qyInput, root.Name, root.Prefix, root.NodeType); props |= Props.NonFlat; break; case Axis.AxisType.FollowingSibling: result = new FollSiblingQuery(qyInput, root.Name, root.Prefix, root.NodeType); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } break; case Axis.AxisType.PrecedingSibling: result = new PreSiblingQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Attribute: result = new AttributeQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Self: result = new XPathSelfQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Namespace: if ((root.NodeType == XPathNodeType.All || root.NodeType == XPathNodeType.Element || root.NodeType == XPathNodeType.Attribute) && root.Prefix.Length == 0) { result = new NamespaceQuery(qyInput, root.Name, root.Prefix, root.NodeType); } else { result = new EmptyQuery(); } break; default: throw XPathException.Create(Res.Xp_NotSupported, query); } return result; } private bool CanBeNumber(Query q) { return ( q.StaticType == XPathResultType.Any || q.StaticType == XPathResultType.Number ); } private Query ProcessFilter(Filter root, Flags flags, out Props props) { bool first = ((flags & Flags.Filter) == 0); Props propsCond; Query cond = ProcessNode(root.Condition, Flags.None, out propsCond); if ( CanBeNumber(cond) || (propsCond & (Props.HasPosition | Props.HasLast)) != 0 ) { propsCond |= Props.HasPosition; flags |= Flags.PosFilter; } // We don't want DescendantOverDescendant pattern to be recognized here (in case descendent::foo[expr]/descendant::bar) // So we clean this flag here: flags &= ~Flags.SmartDesc; // ToDo: Instead it would be nice to wrap descendent::foo[expr] into special query that will flatten it -- i.e. // remove all nodes that are descendant of other nodes. This is very easy becuase for sorted nodesets all children // follow its parent. One step caching. This can be easyly done by rightmost DescendantQuery itsef. // Interesting note! Can we garatee that DescendantOverDescendant returns flat nodeset? This defenetely true if it's input is flat. Query qyInput = ProcessNode(root.Input, flags | Flags.Filter, out props); if (root.Input.Type != AstNode.AstType.Filter) { // Props.PosFilter is for nested filters only. // We clean it here to avoid cleaning it in all other ast nodes. props &= ~Props.PosFilter; } if ((propsCond & Props.HasPosition) != 0) { // this condition is positional rightmost filter should be avare of this. props |= Props.PosFilter; } /*merging predicates*/ { FilterQuery qyFilter = qyInput as FilterQuery; if (qyFilter != null && (propsCond & Props.HasPosition) == 0 && qyFilter.Condition.StaticType != XPathResultType.Any) { Query prevCond = qyFilter.Condition; if (prevCond.StaticType == XPathResultType.Number) { prevCond = new LogicalExpr(Operator.Op.EQ, new NodeFunctions(FT.FuncPosition, null), prevCond); } cond = new BooleanExpr(Operator.Op.AND, prevCond, cond); qyInput = qyFilter.qyInput; } } if ((props & Props.PosFilter) != 0 && qyInput is DocumentOrderQuery) { qyInput = ((DocumentOrderQuery)qyInput).input; } if (firstInput == null) { firstInput = qyInput as BaseAxisQuery; } bool merge = (qyInput.Properties & QueryProps.Merge ) != 0; bool reverse = (qyInput.Properties & QueryProps.Reverse) != 0; if ((propsCond & Props.HasPosition) != 0) { if (reverse) { qyInput = new ReversePositionQuery(qyInput); } else if ((propsCond & Props.HasLast) != 0) { qyInput = new ForwardPositionQuery(qyInput); } } if (first && firstInput != null) { if (merge && (props & Props.PosFilter) != 0) { qyInput = new FilterQuery(qyInput, cond, /*noPosition:*/false); Query parent = firstInput.qyInput; if (! (parent is ContextQuery)) { // we don't need to wrap filter with MergeFilterQuery when cardinality is parent <: ? firstInput.qyInput = new ContextQuery(); firstInput = null; return new MergeFilterQuery(parent, qyInput); } firstInput = null; return qyInput; } firstInput = null; } return new FilterQuery(qyInput, cond, /*noPosition:*/(propsCond & Props.HasPosition) == 0); } private Query ProcessOperator(Operator root, out Props props) { Props props1, props2; Query op1 = ProcessNode(root.Operand1, Flags.None, out props1); Query op2 = ProcessNode(root.Operand2, Flags.None, out props2); props = props1 | props2; switch (root.OperatorType) { case Operator.Op.PLUS : case Operator.Op.MINUS : case Operator.Op.MUL : case Operator.Op.MOD : case Operator.Op.DIV: return new NumericExpr(root.OperatorType, op1, op2); case Operator.Op.LT : case Operator.Op.GT : case Operator.Op.LE : case Operator.Op.GE : case Operator.Op.EQ : case Operator.Op.NE : return new LogicalExpr(root.OperatorType, op1, op2); case Operator.Op.OR : case Operator.Op.AND : return new BooleanExpr(root.OperatorType, op1, op2); case Operator.Op.UNION : props |= Props.NonFlat; return new UnionExpr(op1, op2); default : return null; } } private Query ProcessVariable(Variable root) { needContext = true; if (! allowVar) { throw XPathException.Create(Res.Xp_InvalidKeyPattern, query); } return new VariableQuery(root.Localname, root.Prefix); } private Query ProcessFunction(Function root, out Props props) { props = Props.None; Query qy = null; switch (root.TypeOfFunction) { case FT.FuncLast: qy = new NodeFunctions(root.TypeOfFunction, null); props |= Props.HasLast; return qy; case FT.FuncPosition: qy = new NodeFunctions(root.TypeOfFunction, null); props |= Props.HasPosition; return qy; case FT.FuncCount: return new NodeFunctions(FT.FuncCount, ProcessNode((AstNode)(root.ArgumentList[0]), Flags.None, out props) ); case FT.FuncID: qy = new IDQuery(ProcessNode((AstNode)(root.ArgumentList[0]), Flags.None, out props)); props |= Props.NonFlat; return qy; case FT.FuncLocalName: case FT.FuncNameSpaceUri: case FT.FuncName: if (root.ArgumentList != null && root.ArgumentList.Count > 0) { return new NodeFunctions(root.TypeOfFunction, ProcessNode((AstNode)(root.ArgumentList[0]), Flags.None, out props) ); } else { return new NodeFunctions(root.TypeOfFunction, null); } case FT.FuncString: case FT.FuncConcat: case FT.FuncStartsWith: case FT.FuncContains: case FT.FuncSubstringBefore: case FT.FuncSubstringAfter: case FT.FuncSubstring: case FT.FuncStringLength: case FT.FuncNormalize: case FT.FuncTranslate: return new StringFunctions(root.TypeOfFunction, ProcessArguments(root.ArgumentList, out props)); case FT.FuncNumber: case FT.FuncSum: case FT.FuncFloor: case FT.FuncCeiling: case FT.FuncRound: if (root.ArgumentList != null && root.ArgumentList.Count > 0) { return new NumberFunctions(root.TypeOfFunction, ProcessNode((AstNode)root.ArgumentList[0], Flags.None, out props) ); } else { return new NumberFunctions(Function.FunctionType.FuncNumber, null); } case FT.FuncTrue: case FT.FuncFalse: return new BooleanFunctions(root.TypeOfFunction, null); case FT.FuncNot: case FT.FuncLang: case FT.FuncBoolean: return new BooleanFunctions(root.TypeOfFunction, ProcessNode((AstNode)root.ArgumentList[0], Flags.None, out props) ); case FT.FuncUserDefined: needContext = true; if (! allowCurrent && root.Name == "current" && root.Prefix.Length == 0) { throw XPathException.Create(Res.Xp_CurrentNotAllowed); } if (! allowKey && root.Name == "key" && root.Prefix.Length == 0) { throw XPathException.Create(Res.Xp_InvalidKeyPattern, query); } qy = new FunctionQuery(root.Prefix, root.Name, ProcessArguments(root.ArgumentList, out props)); props |= Props.NonFlat; return qy; default: throw XPathException.Create(Res.Xp_NotSupported, query); } } ListProcessArguments(ArrayList args, out Props props) { int numArgs = args != null ? args.Count : 0; List argList = new List (numArgs); props = Props.None; for (int count = 0; count < numArgs; count++) { Props argProps; argList.Add(ProcessNode((AstNode)args[count], Flags.None, out argProps)); props |= argProps; } return argList; } private Query ProcessNode(AstNode root, Flags flags, out Props props) { Debug.Assert(root != null, "root != null"); Query result = null; props = Props.None; switch (root.Type) { case AstNode.AstType.Axis: result = ProcessAxis((Axis)root, flags, out props); break; case AstNode.AstType.Operator: result = ProcessOperator((Operator)root, out props); break; case AstNode.AstType.Filter: result = ProcessFilter((Filter)root, flags, out props); break; case AstNode.AstType.ConstantOperand: result = new OperandQuery(((Operand)root).OperandValue); break; case AstNode.AstType.Variable: result = ProcessVariable((Variable)root); break; case AstNode.AstType.Function: result = ProcessFunction((Function)root, out props); break; case AstNode.AstType.Group: result = new GroupQuery(ProcessNode(((Group)root).GroupNode, Flags.None, out props)); break; case AstNode.AstType.Root: result = new AbsoluteQuery(); break; default: Debug.Assert(false, "Unknown QueryType encountered!!"); break; } return result; } private Query Build(AstNode root, string query) { Reset(); Props props; this.query = query; Query result = ProcessNode(root, Flags.None, out props); return result; } internal Query Build(string query, bool allowVar, bool allowKey) { this.allowVar = allowVar; this.allowKey = allowKey; this.allowCurrent = true; return Build(XPathParser.ParseXPathExpresion(query), query); } internal Query Build(string query, out bool needContext) { Query result = Build(query, true, true); needContext = this.needContext; return result; } internal Query BuildPatternQuery(string query, bool allowVar, bool allowKey) { this.allowVar = allowVar; this.allowKey = allowKey; this.allowCurrent = false; return Build(XPathParser.ParseXPathPattern(query), query); } internal Query BuildPatternQuery(string query, out bool needContext) { Query result = BuildPatternQuery(query, true, true); needContext = this.needContext; return result; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- namespace MS.Internal.Xml.XPath { using System; using System.Xml; using System.Xml.XPath; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using FT = Function.FunctionType; internal sealed class QueryBuilder { // Note: Up->Doun, Down->Up: // For operators order is normal: 1 + 2 --> Operator+(1, 2) // For pathes order is reversed: a/b -> ChildQuery_B(input: ChildQuery_A(input: ContextQuery())) // Input flags. We pass them Up->Down. // Using them upper query set states wich controls how inner query will be built. enum Flags { None = 0x00, SmartDesc = 0x01, PosFilter = 0x02, // Node has this flag set when it has position predicate applied to it Filter = 0x04, // Subtree we compiling will be filtered. i.e. Flag not set on rightmost filter. } // Output props. We return them Down->Up. // These are properties of Query tree we have built already. // These properties are closely related to QueryProps exposed by Query node itself. // They have the following difference: // QueryProps describe property of node they are (belong like Reverse) // these Props describe acumulated properties of the tree (like nonFlat) enum Props { None = 0x00, PosFilter = 0x01, // This filter or inner filter was positional: foo[1] or foo[1][true()] HasPosition = 0x02, // Expression may ask position() of the context HasLast = 0x04, // Expression may ask last() of the context NonFlat = 0x08, // Some nodes may be descendent of otheres } // comment are aproximate. This is my best understanding: private string query; private bool allowVar; private bool allowKey; private bool allowCurrent; private bool needContext; private BaseAxisQuery firstInput; // Input of the leftmost predicate. Set by leftmost predicate, used in rightmost one private void Reset() { needContext = false; } private Query ProcessAxis(Axis root, Flags flags, out Props props) { Query result = null; if (root.Prefix.Length > 0) { needContext = true; } firstInput = null; Query qyInput; { if (root.Input != null) { Flags inputFlags = Flags.None; if ((flags & Flags.PosFilter) == 0) { Axis input = root.Input as Axis; if (input != null) { if ( root.TypeOfAxis == Axis.AxisType.Child && input.TypeOfAxis == Axis.AxisType.DescendantOrSelf && input.NodeType == XPathNodeType.All ) { Query qyGrandInput; if (input.Input != null) { qyGrandInput = ProcessNode(input.Input, Flags.SmartDesc, out props); } else { qyGrandInput = new ContextQuery(); props = Props.None; } result = new DescendantQuery(qyGrandInput, root.Name, root.Prefix, root.NodeType, false, input.AbbrAxis); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } props |= Props.NonFlat; return result; } } if (root.TypeOfAxis == Axis.AxisType.Descendant || root.TypeOfAxis == Axis.AxisType.DescendantOrSelf) { inputFlags |= Flags.SmartDesc; } } qyInput = ProcessNode(root.Input, inputFlags, out props); } else { qyInput = new ContextQuery(); props = Props.None; } } switch (root.TypeOfAxis) { case Axis.AxisType.Ancestor: result = new XPathAncestorQuery(qyInput , root.Name, root.Prefix, root.NodeType, false); props |= Props.NonFlat; break; case Axis.AxisType.AncestorOrSelf: result = new XPathAncestorQuery(qyInput, root.Name, root.Prefix, root.NodeType, true); props |= Props.NonFlat; break; case Axis.AxisType.Child: if ((props & Props.NonFlat) != 0) { result = new CacheChildrenQuery(qyInput, root.Name, root.Prefix, root.NodeType); } else { result = new ChildrenQuery(qyInput, root.Name, root.Prefix, root.NodeType); } break; case Axis.AxisType.Parent: result = new ParentQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Descendant: if ((flags & Flags.SmartDesc) != 0) { result = new DescendantOverDescendantQuery(qyInput, false, root.Name, root.Prefix, root.NodeType, /*abbrAxis:*/false); } else { result = new DescendantQuery(qyInput, root.Name, root.Prefix, root.NodeType, false, /*abbrAxis:*/false); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } } props |= Props.NonFlat; break; case Axis.AxisType.DescendantOrSelf: if ((flags & Flags.SmartDesc) != 0) { result = new DescendantOverDescendantQuery(qyInput, true, root.Name, root.Prefix, root.NodeType, root.AbbrAxis); } else { result = new DescendantQuery(qyInput, root.Name, root.Prefix, root.NodeType, true, root.AbbrAxis); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } } props |= Props.NonFlat; break; case Axis.AxisType.Preceding: result = new PrecedingQuery(qyInput, root.Name, root.Prefix, root.NodeType); props |= Props.NonFlat; break; case Axis.AxisType.Following: result = new FollowingQuery(qyInput, root.Name, root.Prefix, root.NodeType); props |= Props.NonFlat; break; case Axis.AxisType.FollowingSibling: result = new FollSiblingQuery(qyInput, root.Name, root.Prefix, root.NodeType); if ((props & Props.NonFlat) != 0) { result = new DocumentOrderQuery(result); } break; case Axis.AxisType.PrecedingSibling: result = new PreSiblingQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Attribute: result = new AttributeQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Self: result = new XPathSelfQuery(qyInput, root.Name, root.Prefix, root.NodeType); break; case Axis.AxisType.Namespace: if ((root.NodeType == XPathNodeType.All || root.NodeType == XPathNodeType.Element || root.NodeType == XPathNodeType.Attribute) && root.Prefix.Length == 0) { result = new NamespaceQuery(qyInput, root.Name, root.Prefix, root.NodeType); } else { result = new EmptyQuery(); } break; default: throw XPathException.Create(Res.Xp_NotSupported, query); } return result; } private bool CanBeNumber(Query q) { return ( q.StaticType == XPathResultType.Any || q.StaticType == XPathResultType.Number ); } private Query ProcessFilter(Filter root, Flags flags, out Props props) { bool first = ((flags & Flags.Filter) == 0); Props propsCond; Query cond = ProcessNode(root.Condition, Flags.None, out propsCond); if ( CanBeNumber(cond) || (propsCond & (Props.HasPosition | Props.HasLast)) != 0 ) { propsCond |= Props.HasPosition; flags |= Flags.PosFilter; } // We don't want DescendantOverDescendant pattern to be recognized here (in case descendent::foo[expr]/descendant::bar) // So we clean this flag here: flags &= ~Flags.SmartDesc; // ToDo: Instead it would be nice to wrap descendent::foo[expr] into special query that will flatten it -- i.e. // remove all nodes that are descendant of other nodes. This is very easy becuase for sorted nodesets all children // follow its parent. One step caching. This can be easyly done by rightmost DescendantQuery itsef. // Interesting note! Can we garatee that DescendantOverDescendant returns flat nodeset? This defenetely true if it's input is flat. Query qyInput = ProcessNode(root.Input, flags | Flags.Filter, out props); if (root.Input.Type != AstNode.AstType.Filter) { // Props.PosFilter is for nested filters only. // We clean it here to avoid cleaning it in all other ast nodes. props &= ~Props.PosFilter; } if ((propsCond & Props.HasPosition) != 0) { // this condition is positional rightmost filter should be avare of this. props |= Props.PosFilter; } /*merging predicates*/ { FilterQuery qyFilter = qyInput as FilterQuery; if (qyFilter != null && (propsCond & Props.HasPosition) == 0 && qyFilter.Condition.StaticType != XPathResultType.Any) { Query prevCond = qyFilter.Condition; if (prevCond.StaticType == XPathResultType.Number) { prevCond = new LogicalExpr(Operator.Op.EQ, new NodeFunctions(FT.FuncPosition, null), prevCond); } cond = new BooleanExpr(Operator.Op.AND, prevCond, cond); qyInput = qyFilter.qyInput; } } if ((props & Props.PosFilter) != 0 && qyInput is DocumentOrderQuery) { qyInput = ((DocumentOrderQuery)qyInput).input; } if (firstInput == null) { firstInput = qyInput as BaseAxisQuery; } bool merge = (qyInput.Properties & QueryProps.Merge ) != 0; bool reverse = (qyInput.Properties & QueryProps.Reverse) != 0; if ((propsCond & Props.HasPosition) != 0) { if (reverse) { qyInput = new ReversePositionQuery(qyInput); } else if ((propsCond & Props.HasLast) != 0) { qyInput = new ForwardPositionQuery(qyInput); } } if (first && firstInput != null) { if (merge && (props & Props.PosFilter) != 0) { qyInput = new FilterQuery(qyInput, cond, /*noPosition:*/false); Query parent = firstInput.qyInput; if (! (parent is ContextQuery)) { // we don't need to wrap filter with MergeFilterQuery when cardinality is parent <: ? firstInput.qyInput = new ContextQuery(); firstInput = null; return new MergeFilterQuery(parent, qyInput); } firstInput = null; return qyInput; } firstInput = null; } return new FilterQuery(qyInput, cond, /*noPosition:*/(propsCond & Props.HasPosition) == 0); } private Query ProcessOperator(Operator root, out Props props) { Props props1, props2; Query op1 = ProcessNode(root.Operand1, Flags.None, out props1); Query op2 = ProcessNode(root.Operand2, Flags.None, out props2); props = props1 | props2; switch (root.OperatorType) { case Operator.Op.PLUS : case Operator.Op.MINUS : case Operator.Op.MUL : case Operator.Op.MOD : case Operator.Op.DIV: return new NumericExpr(root.OperatorType, op1, op2); case Operator.Op.LT : case Operator.Op.GT : case Operator.Op.LE : case Operator.Op.GE : case Operator.Op.EQ : case Operator.Op.NE : return new LogicalExpr(root.OperatorType, op1, op2); case Operator.Op.OR : case Operator.Op.AND : return new BooleanExpr(root.OperatorType, op1, op2); case Operator.Op.UNION : props |= Props.NonFlat; return new UnionExpr(op1, op2); default : return null; } } private Query ProcessVariable(Variable root) { needContext = true; if (! allowVar) { throw XPathException.Create(Res.Xp_InvalidKeyPattern, query); } return new VariableQuery(root.Localname, root.Prefix); } private Query ProcessFunction(Function root, out Props props) { props = Props.None; Query qy = null; switch (root.TypeOfFunction) { case FT.FuncLast: qy = new NodeFunctions(root.TypeOfFunction, null); props |= Props.HasLast; return qy; case FT.FuncPosition: qy = new NodeFunctions(root.TypeOfFunction, null); props |= Props.HasPosition; return qy; case FT.FuncCount: return new NodeFunctions(FT.FuncCount, ProcessNode((AstNode)(root.ArgumentList[0]), Flags.None, out props) ); case FT.FuncID: qy = new IDQuery(ProcessNode((AstNode)(root.ArgumentList[0]), Flags.None, out props)); props |= Props.NonFlat; return qy; case FT.FuncLocalName: case FT.FuncNameSpaceUri: case FT.FuncName: if (root.ArgumentList != null && root.ArgumentList.Count > 0) { return new NodeFunctions(root.TypeOfFunction, ProcessNode((AstNode)(root.ArgumentList[0]), Flags.None, out props) ); } else { return new NodeFunctions(root.TypeOfFunction, null); } case FT.FuncString: case FT.FuncConcat: case FT.FuncStartsWith: case FT.FuncContains: case FT.FuncSubstringBefore: case FT.FuncSubstringAfter: case FT.FuncSubstring: case FT.FuncStringLength: case FT.FuncNormalize: case FT.FuncTranslate: return new StringFunctions(root.TypeOfFunction, ProcessArguments(root.ArgumentList, out props)); case FT.FuncNumber: case FT.FuncSum: case FT.FuncFloor: case FT.FuncCeiling: case FT.FuncRound: if (root.ArgumentList != null && root.ArgumentList.Count > 0) { return new NumberFunctions(root.TypeOfFunction, ProcessNode((AstNode)root.ArgumentList[0], Flags.None, out props) ); } else { return new NumberFunctions(Function.FunctionType.FuncNumber, null); } case FT.FuncTrue: case FT.FuncFalse: return new BooleanFunctions(root.TypeOfFunction, null); case FT.FuncNot: case FT.FuncLang: case FT.FuncBoolean: return new BooleanFunctions(root.TypeOfFunction, ProcessNode((AstNode)root.ArgumentList[0], Flags.None, out props) ); case FT.FuncUserDefined: needContext = true; if (! allowCurrent && root.Name == "current" && root.Prefix.Length == 0) { throw XPathException.Create(Res.Xp_CurrentNotAllowed); } if (! allowKey && root.Name == "key" && root.Prefix.Length == 0) { throw XPathException.Create(Res.Xp_InvalidKeyPattern, query); } qy = new FunctionQuery(root.Prefix, root.Name, ProcessArguments(root.ArgumentList, out props)); props |= Props.NonFlat; return qy; default: throw XPathException.Create(Res.Xp_NotSupported, query); } } ListProcessArguments(ArrayList args, out Props props) { int numArgs = args != null ? args.Count : 0; List argList = new List (numArgs); props = Props.None; for (int count = 0; count < numArgs; count++) { Props argProps; argList.Add(ProcessNode((AstNode)args[count], Flags.None, out argProps)); props |= argProps; } return argList; } private Query ProcessNode(AstNode root, Flags flags, out Props props) { Debug.Assert(root != null, "root != null"); Query result = null; props = Props.None; switch (root.Type) { case AstNode.AstType.Axis: result = ProcessAxis((Axis)root, flags, out props); break; case AstNode.AstType.Operator: result = ProcessOperator((Operator)root, out props); break; case AstNode.AstType.Filter: result = ProcessFilter((Filter)root, flags, out props); break; case AstNode.AstType.ConstantOperand: result = new OperandQuery(((Operand)root).OperandValue); break; case AstNode.AstType.Variable: result = ProcessVariable((Variable)root); break; case AstNode.AstType.Function: result = ProcessFunction((Function)root, out props); break; case AstNode.AstType.Group: result = new GroupQuery(ProcessNode(((Group)root).GroupNode, Flags.None, out props)); break; case AstNode.AstType.Root: result = new AbsoluteQuery(); break; default: Debug.Assert(false, "Unknown QueryType encountered!!"); break; } return result; } private Query Build(AstNode root, string query) { Reset(); Props props; this.query = query; Query result = ProcessNode(root, Flags.None, out props); return result; } internal Query Build(string query, bool allowVar, bool allowKey) { this.allowVar = allowVar; this.allowKey = allowKey; this.allowCurrent = true; return Build(XPathParser.ParseXPathExpresion(query), query); } internal Query Build(string query, out bool needContext) { Query result = Build(query, true, true); needContext = this.needContext; return result; } internal Query BuildPatternQuery(string query, bool allowVar, bool allowKey) { this.allowVar = allowVar; this.allowKey = allowKey; this.allowCurrent = false; return Build(XPathParser.ParseXPathPattern(query), query); } internal Query BuildPatternQuery(string query, out bool needContext) { Query result = BuildPatternQuery(query, true, true); needContext = this.needContext; return result; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- KernelTypeValidation.cs
- XmlSchemaAppInfo.cs
- TransformerTypeCollection.cs
- CmsInterop.cs
- Stackframe.cs
- OutputWindow.cs
- dtdvalidator.cs
- SessionStateContainer.cs
- WebZone.cs
- HyperLinkField.cs
- GC.cs
- XmlSchemaValidationException.cs
- SafeViewOfFileHandle.cs
- StrongTypingException.cs
- ReturnEventArgs.cs
- HttpCookieCollection.cs
- Handle.cs
- ReadOnlyCollectionBase.cs
- ImageSource.cs
- Exceptions.cs
- BitConverter.cs
- NullableDecimalSumAggregationOperator.cs
- BaseResourcesBuildProvider.cs
- DLinqAssociationProvider.cs
- BamlLocalizabilityResolver.cs
- XmlSchemaExternal.cs
- BitmapFrameEncode.cs
- WorkflowServiceOperationListItem.cs
- TopClause.cs
- ProcessThread.cs
- MediaSystem.cs
- VariableDesigner.xaml.cs
- GeneralTransform3DTo2DTo3D.cs
- PropertyChangeTracker.cs
- oledbmetadatacolumnnames.cs
- XmlElementElement.cs
- StreamAsIStream.cs
- DateTimeFormatInfoScanner.cs
- KeyboardDevice.cs
- SurrogateChar.cs
- StateManagedCollection.cs
- XamlFxTrace.cs
- SafePEFileHandle.cs
- SoapMessage.cs
- Visual.cs
- DropShadowBitmapEffect.cs
- FlowLayoutPanelDesigner.cs
- DateRangeEvent.cs
- SamlAttribute.cs
- DbConnectionPoolOptions.cs
- PlainXmlDeserializer.cs
- TimeoutValidationAttribute.cs
- DataGridView.cs
- StrokeCollectionDefaultValueFactory.cs
- FixedTextContainer.cs
- WebFormDesignerActionService.cs
- UserNamePasswordClientCredential.cs
- ValidationHelper.cs
- _Semaphore.cs
- CombinedGeometry.cs
- ListParagraph.cs
- TraceEventCache.cs
- WorkflowWebHostingModule.cs
- SiteMapDataSourceDesigner.cs
- DashStyle.cs
- MessageSecurityVersionConverter.cs
- returneventsaver.cs
- AspNetRouteServiceHttpHandler.cs
- ImageIndexConverter.cs
- FamilyTypeface.cs
- WebBrowserHelper.cs
- OrderedDictionary.cs
- XmlSchemaDocumentation.cs
- SiteMapNode.cs
- PathGeometry.cs
- FreezableCollection.cs
- FileCodeGroup.cs
- RuntimeVariableList.cs
- SizeAnimation.cs
- WebPartConnectionsCloseVerb.cs
- ToolStripSplitStackLayout.cs
- WorkflowPersistenceService.cs
- Stylesheet.cs
- ExpressionVisitor.cs
- EventlogProvider.cs
- Int16Converter.cs
- PEFileReader.cs
- DataService.cs
- BindUriHelper.cs
- PolyQuadraticBezierSegment.cs
- HtmlMeta.cs
- PcmConverter.cs
- DataGridViewRowCancelEventArgs.cs
- SqlDataSourceStatusEventArgs.cs
- ParseElement.cs
- StorageEntityTypeMapping.cs
- BrowserDefinition.cs
- AccessKeyManager.cs
- RtType.cs
- ListViewInsertedEventArgs.cs