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

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

Developer Fusion