The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Runtime \ NavigatorConstructor

  1. //------------------------------------------------------------------------------
  2. // <copyright file="RtfNavigator.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.Threading;
  17. using System.IO;
  18. using System.Collections;
  19. using System.Globalization;
  20. using System.Text;
  21. using System.Diagnostics;
  22. using System.Xml;
  23. using System.Xml.XPath;
  24. using System.Xml.Schema;
  25. namespace System.Xml.Xsl.Runtime
  26. {
  27.    
  28.     /// <summary>
  29.     /// RtfNavigators store Xslt result-tree-fragments. At runtime, the Xslt library tests to see if a Navigator
  30.     /// is an RtfNavigator in order to enforce certain restrictions, such as prohibiting querying into Rtfs.
  31.     /// Furthermore, Rtfs must store extra serialization information required in order to properly implement the
  32.     /// Xslt disable-output-escaping flag.
  33.     /// </summary>
  34.     internal abstract class RtfNavigator : XPathNavigator
  35.     {
  36.        
  37.         //-----------------------------------------------
  38.         // RtfNavigator
  39.         //-----------------------------------------------
  40.        
  41.         /// <summary>
  42.         /// Preserve serialization hints when deep copying.
  43.         /// </summary>
  44.         public abstract void CopyToWriter(XmlWriter writer);
  45.        
  46.         /// <summary>
  47.         /// Discard serialization hints and return a navigator that actually allows navigation.
  48.         /// </summary>
  49.         public abstract XPathNavigator ToNavigator();
  50.        
  51.        
  52.         //-----------------------------------------------
  53.         // XPathNavigator
  54.         //-----------------------------------------------
  55.        
  56.         /// <summary>
  57.         /// Get the XPath node type of the current node.
  58.         /// </summary>
  59.         public override XPathNodeType NodeType {
  60.             get { return XPathNodeType.Root; }
  61.         }
  62.        
  63.         /// <summary>
  64.         /// Get the local name portion of the current node's name.
  65.         /// </summary>
  66.         public override string LocalName {
  67.             get { return string.Empty; }
  68.         }
  69.        
  70.         /// <summary>
  71.         /// Get the namespace portion of the current node's name.
  72.         /// </summary>
  73.         public override string NamespaceURI {
  74.             get { return string.Empty; }
  75.         }
  76.        
  77.         /// <summary>
  78.         /// Get the name of the current node.
  79.         /// </summary>
  80.         public override string Name {
  81.             get { return string.Empty; }
  82.         }
  83.        
  84.         /// <summary>
  85.         /// Get the prefix portion of the current node's name.
  86.         /// </summary>
  87.         public override string Prefix {
  88.             get { return string.Empty; }
  89.         }
  90.        
  91.         /// <summary>
  92.         /// Return true if this is an element which used a shortcut tag in its Xml 1.0 serialized form.
  93.         /// </summary>
  94.         public override bool IsEmptyElement {
  95.             get { return false; }
  96.         }
  97.        
  98.         /// <summary>
  99.         /// Return the xml name table which was used to atomize all prefixes, local-names, and
  100.         /// namespace uris in the document.
  101.         /// </summary>
  102.         public override XmlNameTable NameTable {
  103.             get {
  104.                 throw new NotSupportedException();
  105.             }
  106.         }
  107.        
  108.         /// <summary>
  109.         /// Position the navigator on the first attribute of the current node and return true. If no attributes
  110.         /// can be found, return false.
  111.         /// </summary>
  112.         public override bool MoveToFirstAttribute()
  113.         {
  114.             throw new NotSupportedException();
  115.         }
  116.        
  117.         /// <summary>
  118.         /// If positioned on an attribute, move to its next sibling attribute. If no attributes can be found,
  119.         /// return false.
  120.         /// </summary>
  121.         public override bool MoveToNextAttribute()
  122.         {
  123.             throw new NotSupportedException();
  124.         }
  125.        
  126.         /// <summary>
  127.         /// Position the navigator on the namespace within the specified scope. If no matching namespace
  128.         /// can be found, return false.
  129.         /// </summary>
  130.         public override bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope)
  131.         {
  132.             throw new NotSupportedException();
  133.         }
  134.        
  135.         /// <summary>
  136.         /// Position the navigator on the next namespace within the specified scope. If no matching namespace
  137.         /// can be found, return false.
  138.         /// </summary>
  139.         public override bool MoveToNextNamespace(XPathNamespaceScope namespaceScope)
  140.         {
  141.             throw new NotSupportedException();
  142.         }
  143.        
  144.         /// <summary>
  145.         /// If the current node is an attribute or namespace (not content), return false. Otherwise,
  146.         /// move to the next content node. Return false if there are no more content nodes.
  147.         /// </summary>
  148.         public override bool MoveToNext()
  149.         {
  150.             throw new NotSupportedException();
  151.         }
  152.        
  153.         /// <summary>
  154.         /// If the current node is an attribute or namespace (not content), return false. Otherwise,
  155.         /// move to the previous (sibling) content node. Return false if there are no previous content nodes.
  156.         /// </summary>
  157.         public override bool MoveToPrevious()
  158.         {
  159.             throw new NotSupportedException();
  160.         }
  161.        
  162.         /// <summary>
  163.         /// Move to the first content-typed child of the current node. Return false if the current
  164.         /// node has no content children.
  165.         /// </summary>
  166.         public override bool MoveToFirstChild()
  167.         {
  168.             throw new NotSupportedException();
  169.         }
  170.        
  171.         /// <summary>
  172.         /// Position the navigator on the parent of the current node. If the current node has no parent,
  173.         /// return false.
  174.         /// </summary>
  175.         public override bool MoveToParent()
  176.         {
  177.             throw new NotSupportedException();
  178.         }
  179.        
  180.         /// <summary>
  181.         /// Position to the navigator to the element whose id is equal to the specified "id" string.
  182.         /// </summary>
  183.         public override bool MoveToId(string id)
  184.         {
  185.             throw new NotSupportedException();
  186.         }
  187.        
  188.         /// <summary>
  189.         /// Returns true if this navigator is positioned to the same node as the "other" navigator. Returns false
  190.         /// if not, or if the "other" navigator is not the same type as this navigator.
  191.         /// </summary>
  192.         public override bool IsSamePosition(XPathNavigator other)
  193.         {
  194.             throw new NotSupportedException();
  195.         }
  196.     }
  197.    
  198.    
  199.     /// <summary>
  200.     /// This navigator is a cursor over a cache that stores Xslt disable-output-escaping flags.
  201.     /// </summary>
  202.     internal sealed class RtfTreeNavigator : RtfNavigator
  203.     {
  204.         private XmlEventCache events;
  205.         private NavigatorConstructor constr;
  206.         private XmlNameTable nameTable;
  207.        
  208.        
  209.         //-----------------------------------------------
  210.         // Constructors
  211.         //-----------------------------------------------
  212.        
  213.         /// <summary>
  214.         /// Create a new navigator over the specified cache of Xml events.
  215.         /// </summary>
  216.         public RtfTreeNavigator(XmlEventCache events, XmlNameTable nameTable)
  217.         {
  218.             this.events = events;
  219.             this.constr = new NavigatorConstructor();
  220.             this.nameTable = nameTable;
  221.         }
  222.        
  223.         /// <summary>
  224.         /// Copy constructor.
  225.         /// </summary>
  226.         public RtfTreeNavigator(RtfTreeNavigator that)
  227.         {
  228.             this.events = that.events;
  229.             this.constr = that.constr;
  230.             this.nameTable = that.nameTable;
  231.         }
  232.        
  233.        
  234.         //-----------------------------------------------
  235.         // RtfNavigator
  236.         //-----------------------------------------------
  237.        
  238.         /// <summary>
  239.         /// Preserve serialization hints when deep copying.
  240.         /// </summary>
  241.         public override void CopyToWriter(XmlWriter writer)
  242.         {
  243.             this.events.EventsToWriter(writer);
  244.         }
  245.        
  246.         /// <summary>
  247.         /// Discard serialization hints and return a navigator that actually allows navigation.
  248.         /// </summary>
  249.         public override XPathNavigator ToNavigator()
  250.         {
  251.             return this.constr.GetNavigator(this.events, this.nameTable);
  252.         }
  253.        
  254.        
  255.         //-----------------------------------------------
  256.         // XPathItem
  257.         //-----------------------------------------------
  258.        
  259.         /// <summary>
  260.         /// Get the string value of the current node, computed using data model dm:string-value rules.
  261.         /// If the node has a typed value, return the string representation of the value. If the node
  262.         /// is not a parent type (comment, text, pi, etc.), get its simple text value. Otherwise,
  263.         /// concatenate all text node descendants of the current node.
  264.         /// </summary>
  265.         public override string Value {
  266.             get { return this.events.EventsToString(); }
  267.         }
  268.        
  269.        
  270.         //-----------------------------------------------
  271.         // XPathNavigator
  272.         //-----------------------------------------------
  273.        
  274.         /// <summary>
  275.         /// Get the base URI of the Rtf.
  276.         /// </summary>
  277.         public override string BaseURI {
  278.             get { return this.events.BaseUri; }
  279.         }
  280.        
  281.         /// <summary>
  282.         /// Create a copy of this navigator, positioned to the same node in the tree.
  283.         /// </summary>
  284.         public override XPathNavigator Clone()
  285.         {
  286.             return new RtfTreeNavigator(this);
  287.         }
  288.        
  289.         /// <summary>
  290.         /// Position this navigator to the same position as the "other" navigator. If the "other" navigator
  291.         /// is not of the same type as this navigator, then return false.
  292.         /// </summary>
  293.         public override bool MoveTo(XPathNavigator other)
  294.         {
  295.             RtfTreeNavigator that = other as RtfTreeNavigator;
  296.             if (that != null) {
  297.                 this.events = that.events;
  298.                 this.constr = that.constr;
  299.                 this.nameTable = that.nameTable;
  300.                 return true;
  301.             }
  302.             return false;
  303.         }
  304.     }
  305.    
  306.    
  307.     /// <summary>
  308.     /// This RtfNavigator specializes the case of a root node having a single text node child. This is a very common
  309.     /// case, such as in <xsl:variable name="foo">bar</xsl:variable>.
  310.     /// </summary>
  311.     internal sealed class RtfTextNavigator : RtfNavigator
  312.     {
  313.         private string text, baseUri;
  314.         private NavigatorConstructor constr;
  315.        
  316.        
  317.         //-----------------------------------------------
  318.         // Constructors
  319.         //-----------------------------------------------
  320.        
  321.         /// <summary>
  322.         /// Create a new navigator having a text node with value = "text" string.
  323.         /// </summary>
  324.         public RtfTextNavigator(string text, string baseUri)
  325.         {
  326.             this.text = text;
  327.             this.baseUri = baseUri;
  328.             this.constr = new NavigatorConstructor();
  329.         }
  330.        
  331.         /// <summary>
  332.         /// Copy constructor.
  333.         /// </summary>
  334.         public RtfTextNavigator(RtfTextNavigator that)
  335.         {
  336.             this.text = that.text;
  337.             this.baseUri = that.baseUri;
  338.             this.constr = that.constr;
  339.         }
  340.        
  341.        
  342.         //-----------------------------------------------
  343.         // RtfNavigator
  344.         //-----------------------------------------------
  345.        
  346.         /// <summary>
  347.         /// Preserve serialization hints when deep copying.
  348.         /// </summary>
  349.         public override void CopyToWriter(XmlWriter writer)
  350.         {
  351.             writer.WriteString(Value);
  352.         }
  353.        
  354.         /// <summary>
  355.         /// Discard serialization hints and return a navigator that actually allows navigation.
  356.         /// </summary>
  357.         public override XPathNavigator ToNavigator()
  358.         {
  359.             return this.constr.GetNavigator(this.text, this.baseUri, new NameTable());
  360.         }
  361.        
  362.        
  363.         //-----------------------------------------------
  364.         // XPathItem
  365.         //-----------------------------------------------
  366.        
  367.         /// <summary>
  368.         /// Get the string value of the current node, computed using data model dm:string-value rules.
  369.         /// If the node has a typed value, return the string representation of the value. If the node
  370.         /// is not a parent type (comment, text, pi, etc.), get its simple text value. Otherwise,
  371.         /// concatenate all text node descendants of the current node.
  372.         /// </summary>
  373.         public override string Value {
  374.             get { return this.text; }
  375.         }
  376.        
  377.        
  378.         //-----------------------------------------------
  379.         // XPathNavigator
  380.         //-----------------------------------------------
  381.        
  382.         /// <summary>
  383.         /// Get the base URI of the Rtf.
  384.         /// </summary>
  385.         public override string BaseURI {
  386.             get { return this.baseUri; }
  387.         }
  388.        
  389.         /// <summary>
  390.         /// Create a copy of this navigator, positioned to the same node in the tree.
  391.         /// </summary>
  392.         public override XPathNavigator Clone()
  393.         {
  394.             return new RtfTextNavigator(this);
  395.         }
  396.        
  397.         /// <summary>
  398.         /// Position this navigator to the same position as the "other" navigator. If the "other" navigator
  399.         /// is not of the same type as this navigator, then return false.
  400.         /// </summary>
  401.         public override bool MoveTo(XPathNavigator other)
  402.         {
  403.             RtfTextNavigator that = other as RtfTextNavigator;
  404.             if (that != null) {
  405.                 this.text = that.text;
  406.                 this.baseUri = that.baseUri;
  407.                 this.constr = that.constr;
  408.                 return true;
  409.             }
  410.             return false;
  411.         }
  412.     }
  413.    
  414.    
  415.     /// <summary>
  416.     /// This class creates a document on the first call to GetNavigator(), and returns a Navigator from it. On
  417.     /// subsequent calls, Navigators from the same document are returned (no new document is created).
  418.     /// </summary>
  419.     internal sealed class NavigatorConstructor
  420.     {
  421.         object cache;
  422.        
  423.         /// <summary>
  424.         /// Create a document from the cache of events. If a document has already been created previously, return it.
  425.         /// This method is thread-safe, and is always guaranteed to return the exact same document, no matter how many
  426.         /// threads have called it concurrently.
  427.         /// </summary>
  428.         public XPathNavigator GetNavigator(XmlEventCache events, XmlNameTable nameTable)
  429.         {
  430.             if (this.cache == null) {
  431.                 // Create XPathDocument from event cache
  432.                 XPathDocument doc = new XPathDocument(nameTable);
  433.                 XmlRawWriter writer = doc.LoadFromWriter(XPathDocument.LoadFlags.AtomizeNames | (events.HasRootNode ? XPathDocument.LoadFlags.None : XPathDocument.LoadFlags.Fragment), events.BaseUri);
  434.                
  435.                 events.EventsToWriter(writer);
  436.                 writer.Close();
  437.                
  438.                 this.cache = doc;
  439.             }
  440.            
  441.             return ((XPathDocument)this.cache).CreateNavigator();
  442.         }
  443.        
  444.         /// <summary>
  445.         /// Create a document containing a root node and a single text node child with "text" as its text value.
  446.         /// This method is thread-safe, and is always guaranteed to return the exact same document, no matter how many
  447.         /// threads have called it concurrently.
  448.         /// </summary>
  449.         public XPathNavigator GetNavigator(string text, string baseUri, XmlNameTable nameTable)
  450.         {
  451.             if (this.cache == null) {
  452.                 // Create XPathDocument
  453.                 XPathDocument doc = new XPathDocument(nameTable);
  454.                 XmlRawWriter writer = doc.LoadFromWriter(XPathDocument.LoadFlags.AtomizeNames, baseUri);
  455.                 writer.WriteString(text);
  456.                 writer.Close();
  457.                
  458.                 this.cache = doc;
  459.             }
  460.            
  461.             return ((XPathDocument)this.cache).CreateNavigator();
  462.         }
  463.     }
  464. }

Developer Fusion