protected BaseAxisQuery(BaseAxisQuery other) : base(other) { this.qyInput = Clone(other.qyInput); this.name = other.name; this.prefix = other.prefix; this.nsUri = other.nsUri; this.typeTest = other.typeTest; this.nameTest = other.nameTest; this.position = other.position; this.currentNode = other.currentNode; }
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(SR.Xp_NotSupported, _query); } return result; }
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 because for sorted nodesets all children // follow its parent. One step caching. This can be easily done by rightmost DescendantQuery itself. // Interesting note! Can we guarantee that DescendantOverDescendant returns flat nodeset? This definitely 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 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; 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 ProcessAxis(Axis root, Flags flags, out Props props) { Query qyParent = null; Query query2; if (root.Prefix.Length > 0) { this.needContext = true; } this.firstInput = null; if (root.Input != null) { Flags none = Flags.None; if ((flags & Flags.PosFilter) == Flags.None) { Axis input = root.Input as Axis; if (((input != null) && (root.TypeOfAxis == Axis.AxisType.Child)) && ((input.TypeOfAxis == Axis.AxisType.DescendantOrSelf) && (input.NodeType == XPathNodeType.All))) { Query query3; if (input.Input != null) { query3 = this.ProcessNode(input.Input, Flags.SmartDesc, out props); } else { query3 = new ContextQuery(); props = Props.None; } qyParent = new DescendantQuery(query3, root.Name, root.Prefix, root.NodeType, false, input.AbbrAxis); if ((props & Props.NonFlat) != Props.None) { qyParent = new DocumentOrderQuery(qyParent); } props |= Props.NonFlat; return qyParent; } if ((root.TypeOfAxis == Axis.AxisType.Descendant) || (root.TypeOfAxis == Axis.AxisType.DescendantOrSelf)) { none |= Flags.SmartDesc; } } query2 = this.ProcessNode(root.Input, none, out props); } else { query2 = new ContextQuery(); props = Props.None; } switch (root.TypeOfAxis) { case Axis.AxisType.Ancestor: qyParent = new XPathAncestorQuery(query2, root.Name, root.Prefix, root.NodeType, false); props |= Props.NonFlat; return qyParent; case Axis.AxisType.AncestorOrSelf: qyParent = new XPathAncestorQuery(query2, root.Name, root.Prefix, root.NodeType, true); props |= Props.NonFlat; return qyParent; case Axis.AxisType.Attribute: return new AttributeQuery(query2, root.Name, root.Prefix, root.NodeType); case Axis.AxisType.Child: if ((props & Props.NonFlat) == Props.None) { return new ChildrenQuery(query2, root.Name, root.Prefix, root.NodeType); } return new CacheChildrenQuery(query2, root.Name, root.Prefix, root.NodeType); case Axis.AxisType.Descendant: if ((flags & Flags.SmartDesc) == Flags.None) { qyParent = new DescendantQuery(query2, root.Name, root.Prefix, root.NodeType, false, false); if ((props & Props.NonFlat) != Props.None) { qyParent = new DocumentOrderQuery(qyParent); } break; } qyParent = new DescendantOverDescendantQuery(query2, false, root.Name, root.Prefix, root.NodeType, false); break; case Axis.AxisType.DescendantOrSelf: if ((flags & Flags.SmartDesc) == Flags.None) { qyParent = new DescendantQuery(query2, root.Name, root.Prefix, root.NodeType, true, root.AbbrAxis); if ((props & Props.NonFlat) != Props.None) { qyParent = new DocumentOrderQuery(qyParent); } } else { qyParent = new DescendantOverDescendantQuery(query2, true, root.Name, root.Prefix, root.NodeType, root.AbbrAxis); } props |= Props.NonFlat; return qyParent; case Axis.AxisType.Following: qyParent = new FollowingQuery(query2, root.Name, root.Prefix, root.NodeType); props |= Props.NonFlat; return qyParent; case Axis.AxisType.FollowingSibling: qyParent = new FollSiblingQuery(query2, root.Name, root.Prefix, root.NodeType); if ((props & Props.NonFlat) != Props.None) { qyParent = new DocumentOrderQuery(qyParent); } return qyParent; case Axis.AxisType.Namespace: if ((((root.NodeType == XPathNodeType.All) || (root.NodeType == XPathNodeType.Element)) || (root.NodeType == XPathNodeType.Attribute)) && (root.Prefix.Length == 0)) { return new NamespaceQuery(query2, root.Name, root.Prefix, root.NodeType); } return new EmptyQuery(); case Axis.AxisType.Parent: return new ParentQuery(query2, root.Name, root.Prefix, root.NodeType); case Axis.AxisType.Preceding: qyParent = new PrecedingQuery(query2, root.Name, root.Prefix, root.NodeType); props |= Props.NonFlat; return qyParent; case Axis.AxisType.PrecedingSibling: return new PreSiblingQuery(query2, root.Name, root.Prefix, root.NodeType); case Axis.AxisType.Self: return new XPathSelfQuery(query2, root.Name, root.Prefix, root.NodeType); default: throw XPathException.Create("Xp_NotSupported", this.query); } props |= Props.NonFlat; return qyParent; }
private Query ProcessFilter(MS.Internal.Xml.XPath.Filter root, Flags flags, out Props props) { Props props2; bool flag = (flags & Flags.Filter) == Flags.None; Query q = this.ProcessNode(root.Condition, Flags.None, out props2); if (this.CanBeNumber(q) || ((props2 & (Props.HasLast | Props.HasPosition)) != Props.None)) { props2 |= Props.HasPosition; flags |= Flags.PosFilter; } flags &= ~Flags.SmartDesc; Query input = this.ProcessNode(root.Input, flags | Flags.Filter, out props); if (root.Input.Type != AstNode.AstType.Filter) { props &= ~Props.PosFilter; } if ((props2 & Props.HasPosition) != Props.None) { props |= Props.PosFilter; } FilterQuery query3 = input as FilterQuery; if (((query3 != null) && ((props2 & Props.HasPosition) == Props.None)) && (query3.Condition.StaticType != XPathResultType.Any)) { Query condition = query3.Condition; if (condition.StaticType == XPathResultType.Number) { condition = new LogicalExpr(Operator.Op.EQ, new NodeFunctions(Function.FunctionType.FuncPosition, null), condition); } q = new BooleanExpr(Operator.Op.AND, condition, q); input = query3.qyInput; } if (((props & Props.PosFilter) != Props.None) && (input is DocumentOrderQuery)) { input = ((DocumentOrderQuery) input).input; } if (this.firstInput == null) { this.firstInput = input as BaseAxisQuery; } bool flag2 = (input.Properties & QueryProps.Merge) != QueryProps.None; bool flag3 = (input.Properties & QueryProps.Reverse) != QueryProps.None; if ((props2 & Props.HasPosition) != Props.None) { if (flag3) { input = new ReversePositionQuery(input); } else if ((props2 & Props.HasLast) != Props.None) { input = new ForwardPositionQuery(input); } } if (flag && (this.firstInput != null)) { if (flag2 && ((props & Props.PosFilter) != Props.None)) { input = new FilterQuery(input, q, false); Query qyInput = this.firstInput.qyInput; if (!(qyInput is ContextQuery)) { this.firstInput.qyInput = new ContextQuery(); this.firstInput = null; return new MergeFilterQuery(qyInput, input); } this.firstInput = null; return input; } this.firstInput = null; } return new FilterQuery(input, q, (props2 & Props.HasPosition) == Props.None); }