1 //------------------------------------------------------------------------------ 2 // <copyright file="KeyMatchBuilder.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // <owner current="true" primary="true">Microsoft</owner> 6 //------------------------------------------------------------------------------ 7 using System; 8 using System.Diagnostics; 9 using System.Collections; 10 using System.Collections.Generic; 11 using System.Xml; 12 using System.Xml.XPath; 13 using MS.Internal.Xml; 14 using System.Xml.Xsl.XPath; 15 using System.Xml.Xsl.Qil; 16 17 namespace System.Xml.Xsl.Xslt { 18 19 internal class KeyMatchBuilder : XPathBuilder, XPathPatternParser.IPatternBuilder { 20 private int depth = 0; 21 PathConvertor convertor; 22 KeyMatchBuilder(IXPathEnvironment env)23 public KeyMatchBuilder(IXPathEnvironment env) : base(env) { 24 convertor = new PathConvertor(env.Factory); 25 } 26 StartBuild()27 public override void StartBuild() { 28 Debug.Assert(0 <= depth && depth <= 1, "this shouldn't happen"); 29 if (depth == 0) { 30 base.StartBuild(); 31 } 32 depth ++; 33 } 34 EndBuild(QilNode result)35 public override QilNode EndBuild(QilNode result) { 36 depth --; 37 Debug.Assert(0 <= depth && depth <= 1, "this shouldn't happen"); 38 if (result == null) { // special door to clean builder state in exception handlers 39 return base.EndBuild(result); 40 } 41 if (depth == 0) { 42 Debug.Assert(base.numFixupLast == 0); 43 Debug.Assert(base.numFixupPosition == 0); 44 result = convertor.ConvertReletive2Absolute(result, base.fixupCurrent); 45 result = base.EndBuild(result); 46 } 47 return result; 48 } 49 50 // -------------------------------------- GetPredicateBuilder() --------------------------------------- 51 GetPredicateBuilder(QilNode ctx)52 public virtual IXPathBuilder<QilNode> GetPredicateBuilder(QilNode ctx) { 53 return this; 54 } 55 56 // This code depends on particula shapes that XPathBuilder generates. 57 // It works only on pathes. 58 // ToDo: We can do better here. 59 internal class PathConvertor : QilReplaceVisitor { 60 new XPathQilFactory f; 61 QilNode fixup; PathConvertor(XPathQilFactory f)62 public PathConvertor(XPathQilFactory f) : base (f.BaseFactory) { 63 this.f = f; 64 } 65 ConvertReletive2Absolute(QilNode node, QilNode fixup)66 public QilNode ConvertReletive2Absolute(QilNode node, QilNode fixup) { 67 QilDepthChecker.Check(node); 68 Debug.Assert(node != null); 69 Debug.Assert(fixup != null); 70 this.fixup = fixup; 71 return this.Visit(node); 72 } 73 74 // transparantly passing through Union and DocOrder Visit(QilNode n)75 protected override QilNode Visit(QilNode n) { 76 if ( 77 n.NodeType == QilNodeType.Union || 78 n.NodeType == QilNodeType.DocOrderDistinct || 79 n.NodeType == QilNodeType.Filter || 80 n.NodeType == QilNodeType.Loop 81 ) { 82 return base.Visit(n); 83 } 84 return n; 85 } 86 // Filers that travers Content being converted to global travers: 87 // Filter($j= ... Filter($i = Content(fixup), ...)) -> Filter($j= ... Filter($i = Loop($j = DesendentOrSelf(Root(fixup)), Content($j), ...))) VisitLoop(QilLoop n)88 protected override QilNode VisitLoop(QilLoop n) { 89 if (n.Variable.Binding.NodeType == QilNodeType.Root || n.Variable.Binding.NodeType == QilNodeType.Deref) { 90 // This is absolute path already. We shouldn't touch it 91 return n; 92 } 93 if (n.Variable.Binding.NodeType == QilNodeType.Content) { 94 // This is "begin" of reletive path. Let's rewrite it as absolute: 95 QilUnary content = (QilUnary)n.Variable.Binding; 96 Debug.Assert(content.Child == this.fixup, "Unexpected content node"); 97 QilIterator it = f.For(f.DescendantOrSelf(f.Root(this.fixup))); 98 content.Child = it; 99 n.Variable.Binding = f.Loop(it, content); 100 return n; 101 } 102 n.Variable.Binding = Visit(n.Variable.Binding); 103 return n; 104 } 105 VisitFilter(QilLoop n)106 protected override QilNode VisitFilter(QilLoop n) { 107 return VisitLoop(n); 108 } 109 } 110 } 111 } 112