Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / XmlUtils / System / Xml / Xsl / Xslt / XPathPatternBuilder.cs / 1305376 / XPathPatternBuilder.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Xml.XPath; using System.Xml.Schema; using System.Xml.Xsl.Qil; using System.Xml.Xsl.XPath; namespace System.Xml.Xsl.Xslt { using T = XmlQueryTypeFactory; internal class XPathPatternBuilder : XPathPatternParser.IPatternBuilder { private XPathPredicateEnvironment predicateEnvironment; private XPathBuilder predicateBuilder; private bool inTheBuild; private XPathQilFactory f; private QilNode fixupNode; private IXPathEnvironment environment; public XPathPatternBuilder(IXPathEnvironment environment) { Debug.Assert(environment != null); this.environment = environment; this.f = environment.Factory; this.predicateEnvironment = new XPathPredicateEnvironment(environment); this.predicateBuilder = new XPathBuilder(predicateEnvironment); this.fixupNode = f.Unknown(T.NodeNotRtfS); } public QilNode FixupNode { get { return fixupNode; } } public virtual void StartBuild() { Debug.Assert(! inTheBuild, "XPathBuilder is buisy!"); inTheBuild = true; return; } [Conditional("DEBUG")] public void AssertFilter(QilLoop filter) { Debug.Assert(filter.NodeType == QilNodeType.Filter, "XPathPatternBuilder expected to generate list of Filters on top level"); Debug.Assert(filter.Variable.XmlType.IsSubtypeOf(T.NodeNotRtf)); Debug.Assert(filter.Variable.Binding.NodeType == QilNodeType.Unknown); // fixupNode Debug.Assert(filter.Body.XmlType.IsSubtypeOf(T.Boolean)); } private void FixupFilterBinding(QilLoop filter, QilNode newBinding) { AssertFilter(filter); filter.Variable.Binding = newBinding; } public virtual QilNode EndBuild(QilNode result) { Debug.Assert(inTheBuild, "StartBuild() wasn't called"); if (result == null) { // Special door to clean builder state in exception handlers } inTheBuild = false; return result; } public QilNode Operator(XPathOperator op, QilNode left, QilNode right) { Debug.Assert(op == XPathOperator.Union); Debug.Assert(left != null); Debug.Assert(right != null); // It is important to not create nested lists here Debug.Assert(right.NodeType == QilNodeType.Filter, "LocationPathPattern must be compiled into a filter"); if (left.NodeType == QilNodeType.Sequence) { ((QilList)left).Add(right); return left; } else { Debug.Assert(left.NodeType == QilNodeType.Filter, "LocationPathPattern must be compiled into a filter"); return f.Sequence(left, right); } } private static QilLoop BuildAxisFilter(QilPatternFactory f, QilIterator itr, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri) { QilNode nameTest = ( name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) : // ns:bar || bar nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:* name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) : // *:foo /*name == nsUri == null*/ f.True() // * ); XmlNodeKindFlags intersection = XPathBuilder.AxisTypeMask(itr.XmlType.NodeKinds, nodeType, xpathAxis); QilNode typeTest = ( intersection == 0 ? f.False() : // input & required doesn't intersect intersection == itr.XmlType.NodeKinds ? f.True() : // input is subset of required /*else*/ f.IsType(itr, T.NodeChoice(intersection)) ); QilLoop filter = f.BaseFactory.Filter(itr, f.And(typeTest, nameTest)); filter.XmlType = T.PrimeProduct(T.NodeChoice(intersection), filter.XmlType.Cardinality); return filter; } public QilNode Axis(XPathAxis xpathAxis, XPathNodeType nodeType, string prefix, string name) { Debug.Assert( xpathAxis == XPathAxis.Child || xpathAxis == XPathAxis.Attribute || xpathAxis == XPathAxis.DescendantOrSelf || xpathAxis == XPathAxis.Root ); QilLoop result; double priority; switch (xpathAxis) { case XPathAxis.DescendantOrSelf : Debug.Assert(nodeType == XPathNodeType.All && prefix == null && name == null, " // is the only d-o-s axes that we can have in pattern"); return f.Nop(this.fixupNode); // We using Nop as a flag that DescendantOrSelf exis was used between steps. case XPathAxis.Root : QilIterator i; result = f.BaseFactory.Filter(i = f.For(fixupNode), f.IsType(i, T.Document)); priority = 0.5; break; default : string nsUri = prefix == null ? null : this.environment.ResolvePrefix(prefix); result = BuildAxisFilter(f, f.For(fixupNode), xpathAxis, nodeType, name, nsUri); switch (nodeType) { case XPathNodeType.Element : case XPathNodeType.Attribute : if (name != null) { priority = 0; } else { if (prefix != null) { priority = -0.25; } else { priority = -0.5; } } break; case XPathNodeType.ProcessingInstruction : priority = name != null ? 0 : -0.5; break; default: priority = -0.5; break; } break; } SetPriority(result, priority); SetLastParent(result, result); return result; } // a/b/c -> self::c[parent::b[parent::a]] // a/b//c -> self::c[ancestor::b[parent::a]] // a/b -> self::b[parent::a] // -> JoinStep(Axis('a'), Axis('b')) // -> Filter('b' & Parent(Filter('a'))) // a//b // -> JoinStep(Axis('a'), JoingStep(Axis(DescendantOrSelf), Axis('b'))) // -> JoinStep(Filter('a'), JoingStep(Nop(null), Filter('b'))) // -> JoinStep(Filter('a'), Nop(Filter('b'))) // -> Filter('b' & Ancestor(Filter('a'))) public QilNode JoinStep(QilNode left, QilNode right) { Debug.Assert(left != null); Debug.Assert(right != null); if (left.NodeType == QilNodeType.Nop) { QilUnary nop = (QilUnary)left; Debug.Assert(nop.Child == this.fixupNode); nop.Child = right; // We use Nop as a flag that DescendantOrSelf axis was used between steps. return nop; } Debug.Assert(GetLastParent(left) == left, "Left is always single axis and never the step"); Debug.Assert(left.NodeType == QilNodeType.Filter); CleanAnnotation(left); QilLoop parentFilter = (QilLoop) left; bool ancestor = false; { if (right.NodeType == QilNodeType.Nop) { ancestor = true; QilUnary nop = (QilUnary)right; Debug.Assert(nop.Child != null); right = nop.Child; } } Debug.Assert(right.NodeType == QilNodeType.Filter); QilLoop lastParent = GetLastParent(right); FixupFilterBinding(parentFilter, ancestor ? f.Ancestor(lastParent.Variable) : f.Parent(lastParent.Variable)); lastParent.Body = f.And(lastParent.Body, f.Not(f.IsEmpty(parentFilter))); SetPriority(right, 0.5); SetLastParent(right, parentFilter); return right; } public QilNode Predicate(QilNode node, QilNode condition, bool isReverseStep) { Debug.Assert(isReverseStep == false, "patterns can't have reverse axe"); QilLoop nodeFilter = (QilLoop) node; if (condition.XmlType.TypeCode == XmlTypeCode.Double) { predicateEnvironment.SetContext(nodeFilter); condition = f.Eq(condition, predicateEnvironment.GetPosition()); } else { condition = f.ConvertToBoolean(condition); } nodeFilter.Body = f.And(nodeFilter.Body, condition); SetPriority(node, 0.5); return node; } public QilNode Function(string prefix, string name, IListargs) { Debug.Assert(prefix.Length == 0); QilIterator i = f.For(fixupNode); QilNode matches; if (name == "id") { Debug.Assert( args.Count == 1 && args[0].NodeType == QilNodeType.LiteralString, "Function id() must have one literal string argument" ); matches = f.Id(i, args[0]); } else { Debug.Assert(name == "key", "Unexpected function"); Debug.Assert( args.Count == 2 && args[0].NodeType == QilNodeType.LiteralString && args[1].NodeType == QilNodeType.LiteralString, "Function key() must have two literal string arguments" ); matches = environment.ResolveFunction(prefix, name, args, new XsltFunctionFocus(i)); } QilIterator j; QilLoop result = f.BaseFactory.Filter(i, f.Not(f.IsEmpty(f.Filter(j = f.For(matches), f.Is(j, i))))); SetPriority(result, 0.5); SetLastParent(result, result); return result; } public QilNode String(string value) { return f.String(value); } // As argument of id() or key() function public QilNode Number(double value) { return UnexpectedToken("Literal number"); } public QilNode Variable(string prefix, string name) { return UnexpectedToken("Variable"); } private QilNode UnexpectedToken(string tokenName) { string prompt = string.Format(CultureInfo.InvariantCulture, "Internal Error: {0} is not allowed in XSLT pattern outside of predicate.", tokenName); Debug.Assert(false, prompt); throw new Exception(prompt); } // -------------------------------------- Priority / Parent --------------------------------------- private class Annotation { public double Priority; public QilLoop Parent; } public static void SetPriority(QilNode node, double priority) { Annotation ann = (Annotation)node.Annotation ?? new Annotation(); ann.Priority = priority; node.Annotation = ann; } public static double GetPriority(QilNode node) { return ((Annotation)node.Annotation).Priority; } private static void SetLastParent(QilNode node, QilLoop parent) { Debug.Assert(parent.NodeType == QilNodeType.Filter); Annotation ann = (Annotation)node.Annotation ?? new Annotation(); ann.Parent = parent; node.Annotation = ann; } private static QilLoop GetLastParent(QilNode node) { return ((Annotation)node.Annotation).Parent; } public static void CleanAnnotation(QilNode node) { node.Annotation = null; } // -------------------------------------- GetPredicateBuilder() --------------------------------------- public IXPathBuilder GetPredicateBuilder(QilNode ctx) { QilLoop context = (QilLoop) ctx; Debug.Assert(context != null, "Predicate always has step so it can't have context == null"); Debug.Assert(context.Variable.NodeType == QilNodeType.For, "It shouldn't be Let, becaus predicates in PatternBuilder don't produce cached tuples."); predicateEnvironment.SetContext(context); return predicateBuilder; } private class XPathPredicateEnvironment : IXPathEnvironment { private IXPathEnvironment baseEnvironment; private QilLoop baseContext; private XPathQilFactory f; private Cloner cloner; public XPathPredicateEnvironment(IXPathEnvironment baseEnvironment) { this.baseEnvironment = baseEnvironment; this.f = baseEnvironment.Factory; cloner = new Cloner(f.BaseFactory); } public void SetContext(QilLoop filter) { this.baseContext = filter; } /* --------------------------------------------------------------------------- IXPathEnvironment interface */ public XPathQilFactory Factory { get { return f; } } public QilNode ResolveVariable(string prefix, string name) { return baseEnvironment.ResolveVariable(prefix, name); } public QilNode ResolveFunction(string prefix, string name, IList args, IFocus env) { return baseEnvironment.ResolveFunction(prefix, name, args, env); } public string ResolvePrefix(string prefix) { return baseEnvironment.ResolvePrefix(prefix); } public QilNode GetCurrent() { return baseContext.Variable; } public QilNode GetPosition() { QilLoop clone = (QilLoop) cloner.Clone(baseContext); XmlNodeKindFlags nodeKinds = baseContext.XmlType.NodeKinds; // baseContext either always returns attributes (attribute::), or never returns attributes or namespaces (child::) if (nodeKinds == XmlNodeKindFlags.Attribute) { QilIterator i = f.For(f.Parent(GetCurrent())); clone.Variable.Binding = f.Content(i); clone.Body = f.And(clone.Body, f.Before(clone.Variable, GetCurrent())); clone = f.BaseFactory.Loop(i, clone); } else { Debug.Assert((nodeKinds & (XmlNodeKindFlags.Attribute | XmlNodeKindFlags.Namespace)) == XmlNodeKindFlags.None); clone.Variable.Binding = f.PrecedingSibling(GetCurrent()); } return f.Add(f.Double(1), f.XsltConvert(f.Length(clone), T.DoubleX)); } public QilNode GetLast() { QilLoop clone = (QilLoop) cloner.Clone(baseContext); QilIterator i = f.For(f.Parent(GetCurrent())); clone.Variable.Binding = f.Content(i); return f.XsltConvert(f.Length(f.Loop(i, clone)), T.DoubleX); } internal class Cloner : QilCloneVisitor { public Cloner(QilFactory f) : base(f) {} // Expressions we are cloning have fixup node of type QilNodeType.Unknown // This node will be replaced anyway so we leave it as it is protected override QilNode VisitUnknown(QilNode n) { return n; } } } private class XsltFunctionFocus : IFocus { private QilIterator current; public XsltFunctionFocus(QilIterator current) { Debug.Assert(current != null); this.current = current; } /* --------------------------------------------------------------------------- IFocus interface */ public QilNode GetCurrent() { return current; } public QilNode GetPosition() { Debug.Fail("GetPosition() must not be called"); return null; } public QilNode GetLast() { Debug.Fail("GetLast() must not be called"); return null; } } } } // 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
- ConstNode.cs
- CodeMemberField.cs
- WorkerRequest.cs
- TempFiles.cs
- WebConfigurationManager.cs
- BoundPropertyEntry.cs
- DynamicActivityXamlReader.cs
- SqlDataSourceSummaryPanel.cs
- ListViewUpdatedEventArgs.cs
- Set.cs
- DecoderReplacementFallback.cs
- UndoUnit.cs
- WebPartCloseVerb.cs
- DependencyPropertyValueSerializer.cs
- DataGridViewCellStyle.cs
- DesignDataSource.cs
- PassportAuthenticationModule.cs
- HttpListenerRequest.cs
- PhysicalOps.cs
- ProfileSettingsCollection.cs
- HorizontalAlignConverter.cs
- MSG.cs
- ClientSideQueueItem.cs
- RSAPKCS1SignatureDeformatter.cs
- MemberCollection.cs
- RegexCompilationInfo.cs
- SharedUtils.cs
- ContextQuery.cs
- PointF.cs
- OracleParameterCollection.cs
- indexingfiltermarshaler.cs
- PageVisual.cs
- SHA384Managed.cs
- Decimal.cs
- ApplicationActivator.cs
- ObjectStateFormatter.cs
- SEHException.cs
- SqlErrorCollection.cs
- ExpandoClass.cs
- ProtocolsConfigurationEntry.cs
- MonitorWrapper.cs
- Comparer.cs
- FunctionMappingTranslator.cs
- NeutralResourcesLanguageAttribute.cs
- PersonalizationAdministration.cs
- PointIndependentAnimationStorage.cs
- PropertyGroupDescription.cs
- Vector3dCollection.cs
- Panel.cs
- ProfileService.cs
- iisPickupDirectory.cs
- SlipBehavior.cs
- XslTransform.cs
- MatrixValueSerializer.cs
- SiteMapNodeItemEventArgs.cs
- ProgressBar.cs
- RegexBoyerMoore.cs
- InternalsVisibleToAttribute.cs
- XslTransform.cs
- ClientBuildManagerTypeDescriptionProviderBridge.cs
- UnsafeNativeMethods.cs
- CubicEase.cs
- CachedFontFace.cs
- RepeatButton.cs
- ModelUIElement3D.cs
- UInt64.cs
- AutomationPatternInfo.cs
- RTLAwareMessageBox.cs
- TrackingProfileSerializer.cs
- CaseInsensitiveHashCodeProvider.cs
- PrePrepareMethodAttribute.cs
- BindingExpression.cs
- WindowsPen.cs
- SafeNativeMethods.cs
- MultiTrigger.cs
- LinqDataSourceSelectEventArgs.cs
- BinaryMessageEncodingElement.cs
- PageCodeDomTreeGenerator.cs
- ImageMap.cs
- ZipIOExtraFieldElement.cs
- XmlFormatReaderGenerator.cs
- XmlSchemaAnnotated.cs
- ping.cs
- WorkerRequest.cs
- ImageCreator.cs
- EntityDescriptor.cs
- ReversePositionQuery.cs
- EntityDesignerDataSourceView.cs
- Decorator.cs
- LinkedResourceCollection.cs
- ChannelProtectionRequirements.cs
- ScrollableControlDesigner.cs
- TableCell.cs
- Comparer.cs
- ReadOnlyHierarchicalDataSource.cs
- HtmlButton.cs
- SimpleType.cs
- SqlProcedureAttribute.cs
- CodeThrowExceptionStatement.cs
- PrivacyNoticeElement.cs