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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Focus.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.Collections.Generic;
  16. using System.Diagnostics;
  17. using System.Xml.Xsl.XPath;
  18. using System.Xml.Xsl.Qil;
  19. namespace System.Xml.Xsl.Xslt
  20. {
  21.     using T = XmlQueryTypeFactory;
  22.    
  23.     // <spec>http://www.w3.org/TR/xslt20/#dt-singleton-focus</spec>
  24.     internal enum SingletonFocusType
  25.     {
  26.         // No context set
  27.         // Used to prevent bugs
  28.         None,
  29.        
  30.         // Document node of the document containing the initial context node
  31.         // Used while compiling global variables and params
  32.         InitialDocumentNode,
  33.        
  34.         // Initial context node for the transformation
  35.         // Used while compiling initial apply-templates
  36.         InitialContextNode,
  37.        
  38.         // Context node is specified by iterator
  39.         // Used while compiling keys
  40.         Iterator
  41.     }
  42.    
  43.     internal struct SingletonFocus : IFocus
  44.     {
  45.         private XPathQilFactory f;
  46.         private SingletonFocusType focusType;
  47.         private QilIterator current;
  48.        
  49.         public SingletonFocus(XPathQilFactory f)
  50.         {
  51.             this.f = f;
  52.             focusType = SingletonFocusType.None;
  53.             current = null;
  54.         }
  55.        
  56.         public void SetFocus(SingletonFocusType focusType)
  57.         {
  58.             Debug.Assert(focusType != SingletonFocusType.Iterator);
  59.             this.focusType = focusType;
  60.         }
  61.        
  62.         public void SetFocus(QilIterator current)
  63.         {
  64.             if (current != null) {
  65.                 this.focusType = SingletonFocusType.Iterator;
  66.                 this.current = current;
  67.             }
  68.             else {
  69.                 this.focusType = SingletonFocusType.None;
  70.                 this.current = null;
  71.             }
  72.         }
  73.        
  74.         [Conditional("DEBUG")]
  75.         private void CheckFocus()
  76.         {
  77.             Debug.Assert(focusType != SingletonFocusType.None, "Focus is not set, call SetFocus first");
  78.         }
  79.        
  80.         public QilNode GetCurrent()
  81.         {
  82.             CheckFocus();
  83.             switch (focusType) {
  84.                 case SingletonFocusType.InitialDocumentNode:
  85.                     return f.Root(f.XmlContext());
  86.                 case SingletonFocusType.InitialContextNode:
  87.                     return f.XmlContext();
  88.                 default:
  89.                     Debug.Assert(focusType == SingletonFocusType.Iterator && current != null, "Unexpected singleton focus type");
  90.                     return current;
  91.             }
  92.         }
  93.        
  94.         public QilNode GetPosition()
  95.         {
  96.             CheckFocus();
  97.             return f.Double(1);
  98.         }
  99.        
  100.         public QilNode GetLast()
  101.         {
  102.             CheckFocus();
  103.             return f.Double(1);
  104.         }
  105.     }
  106.    
  107.     internal struct FunctionFocus : IFocus
  108.     {
  109.         private bool isSet;
  110.         private QilParameter current, position, last;
  111.        
  112.         public void StartFocus(IList<QilNode> args, XslFlags flags)
  113.         {
  114.             Debug.Assert(!IsFocusSet, "Focus was already set");
  115.             int argNum = 0;
  116.             if ((flags & XslFlags.Current) != 0) {
  117.                 this.current = (QilParameter)args[argNum++];
  118.                 Debug.Assert(this.current.Name.NamespaceUri == XmlReservedNs.NsXslDebug && this.current.Name.LocalName == "current");
  119.             }
  120.             if ((flags & XslFlags.Position) != 0) {
  121.                 this.position = (QilParameter)args[argNum++];
  122.                 Debug.Assert(this.position.Name.NamespaceUri == XmlReservedNs.NsXslDebug && this.position.Name.LocalName == "position");
  123.             }
  124.             if ((flags & XslFlags.Last) != 0) {
  125.                 this.last = (QilParameter)args[argNum++];
  126.                 Debug.Assert(this.last.Name.NamespaceUri == XmlReservedNs.NsXslDebug && this.last.Name.LocalName == "last");
  127.             }
  128.             this.isSet = true;
  129.         }
  130.         public void StopFocus()
  131.         {
  132.             Debug.Assert(IsFocusSet, "Focus was not set");
  133.             isSet = false;
  134.             this.current = this.position = this.last = null;
  135.         }
  136.         public bool IsFocusSet {
  137.             get { return this.isSet; }
  138.         }
  139.        
  140.         public QilNode GetCurrent()
  141.         {
  142.             Debug.Assert(this.current != null, "Naked current() is not expected in this function");
  143.             return this.current;
  144.         }
  145.        
  146.         public QilNode GetPosition()
  147.         {
  148.             Debug.Assert(this.position != null, "Naked position() is not expected in this function");
  149.             return this.position;
  150.         }
  151.        
  152.         public QilNode GetLast()
  153.         {
  154.             Debug.Assert(this.last != null, "Naked last() is not expected in this function");
  155.             return this.last;
  156.         }
  157.     }
  158.    
  159.     internal struct LoopFocus : IFocus
  160.     {
  161.         private XPathQilFactory f;
  162.         private QilIterator current, cached, last;
  163.        
  164.         public LoopFocus(XPathQilFactory f)
  165.         {
  166.             this.f = f;
  167.             current = cached = last = null;
  168.         }
  169.        
  170.         public void SetFocus(QilIterator current)
  171.         {
  172.             this.current = current;
  173.             cached = last = null;
  174.         }
  175.        
  176.         public bool IsFocusSet {
  177.             get { return current != null; }
  178.         }
  179.        
  180.         public QilNode GetCurrent()
  181.         {
  182.             return current;
  183.         }
  184.        
  185.         public QilNode GetPosition()
  186.         {
  187.             return f.XsltConvert(f.PositionOf(current), T.DoubleX);
  188.         }
  189.        
  190.         public QilNode GetLast()
  191.         {
  192.             if (last == null) {
  193.                 // Create a let that will be fixed up later in ConstructLoop or by LastFixupVisitor
  194.                 last = f.Let(f.Double(0));
  195.             }
  196.             return last;
  197.         }
  198.        
  199.         public void EnsureCache()
  200.         {
  201.             if (cached == null) {
  202.                 cached = f.Let(current.Binding);
  203.                 current.Binding = cached;
  204.             }
  205.         }
  206.        
  207.         public void Sort(QilNode sortKeys)
  208.         {
  209.             if (sortKeys != null) {
  210.                 // If sorting is required, cache the input node-set to support last() within sort key expressions
  211.                 EnsureCache();
  212.                 // The rest of the loop content must be compiled in the context of already sorted node-set
  213.                 current = f.For(f.Sort(current, sortKeys));
  214.             }
  215.         }
  216.        
  217.         public QilLoop ConstructLoop(QilNode body)
  218.         {
  219.             QilLoop result;
  220.             if (last != null) {
  221.                 // last() encountered either in the sort keys or in the body of the current loop
  222.                 EnsureCache();
  223.                 last.Binding = f.XsltConvert(f.Length(cached), T.DoubleX);
  224.             }
  225.             result = f.BaseFactory.Loop(current, body);
  226.             if (last != null) {
  227.                 result = f.BaseFactory.Loop(last, result);
  228.             }
  229.             if (cached != null) {
  230.                 result = f.BaseFactory.Loop(cached, result);
  231.             }
  232.             return result;
  233.         }
  234.     }
  235. }

Developer Fusion