2004-02-13 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Fri, 13 Feb 2004 20:03:33 +0000 (20:03 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Fri, 13 Feb 2004 20:03:33 +0000 (20:03 -0000)
* Added DTMXPathDocumentWriter.cs. It supports DTMXPathNavigator as
  the resulting document tree.
* DTMXPathDocumentBuilder.cs : Code refactory (to get closer to dtm
  writer and commonify tasks they both should do). Reduced initial
  array size (400 to 200, for attribute 800 to 200), and extending
  size from 2x to 4x (to reduce _times_ of allication copy).
* DTMXPathNode.cs : (and all above) added experimental "DTM_CLASS"
  switch, which changes nodes from struct to class. (It will reduce
  memory consumption by 2/3, but will also reduce speed by 2/3.)

svn path=/trunk/mcs/; revision=23069

mcs/class/System.XML/Mono.Xml.XPath/ChangeLog
mcs/class/System.XML/Mono.Xml.XPath/DTMXPathDocumentBuilder.cs
mcs/class/System.XML/Mono.Xml.XPath/DTMXPathDocumentWriter.cs [new file with mode: 0755]
mcs/class/System.XML/Mono.Xml.XPath/DTMXPathNode.cs

index 56504699f70472cb4ce690917d3e6407e82c0378..583016b8cc1ca4eed035bda6ff5cef317c9a21cc 100644 (file)
@@ -1,3 +1,15 @@
+2004-02-13  Atsushi Enomoto <atsushi@ximian.com>
+
+       * Added DTMXPathDocumentWriter.cs. It supports DTMXPathNavigator as
+         the resulting document tree.
+       * DTMXPathDocumentBuilder.cs : Code refactory (to get closer to dtm
+         writer and commonify tasks they both should do). Reduced initial
+         array size (400 to 200, for attribute 800 to 200), and extending 
+         size from 2x to 4x (to reduce _times_ of allication copy).
+       * DTMXPathNode.cs : (and all above) added experimental "DTM_CLASS"
+         switch, which changes nodes from struct to class. (It will reduce
+         memory consumption by 2/3, but will also reduce speed by 2/3.)
+
 2004-01-27  Atsushi Enomoto <atsushi@ximian.com>
 
        * DTMXPathDocumentBuilder.cs : Namespace nodes are incorrectly created.
index 5989f2c1658684355a964dde6a05a680056bc536..59a73904c29ca6346fc9581e7ec96223ce436309 100644 (file)
@@ -6,6 +6,7 @@
 //
 // (C) 2003 Atsushi Enomoto
 //
+//#define DTM_CLASS
 using System;
 using System.Collections;
 using System.IO;
@@ -19,12 +20,12 @@ namespace Mono.Xml.XPath
        public class DTMXPathDocumentBuilder
        {
                public DTMXPathDocumentBuilder (string url)
-                       : this (url, XmlSpace.None, 400)
+                       : this (url, XmlSpace.None, 200)
                {
                }
 
                public DTMXPathDocumentBuilder (string url, XmlSpace space)
-                       : this (url, space, 400)
+                       : this (url, space, 200)
                {
                }
 
@@ -34,12 +35,12 @@ namespace Mono.Xml.XPath
                }
 
                public DTMXPathDocumentBuilder (XmlReader reader)
-                       : this (reader, XmlSpace.None, 400)
+                       : this (reader, XmlSpace.None, 200)
                {
                }
 
                public DTMXPathDocumentBuilder (XmlReader reader, XmlSpace space)
-                       : this (reader, space, 400)
+                       : this (reader, space, 200)
                {
                }
 
@@ -50,8 +51,14 @@ namespace Mono.Xml.XPath
                        lineInfo = reader as IXmlLineInfo;
                        this.xmlSpace = space;
                        this.nameTable = reader.NameTable;
-                       nodeCapacity = nodeCapacity;
-                       attributeCapacity = nodeCapacity * 2;
+                       nodeCapacity = defaultCapacity;
+                       attributeCapacity = nodeCapacity;
+                       idTable = new Hashtable ();
+
+                       nodes = new DTMXPathLinkedNode [nodeCapacity];
+                       attributes = new DTMXPathAttributeNode [attributeCapacity];
+                       namespaces = new DTMXPathNamespaceNode [0];
+
                        Compile ();
                }
                
@@ -60,18 +67,18 @@ namespace Mono.Xml.XPath
                XmlSpace xmlSpace;
                XmlNameTable nameTable;
                IXmlLineInfo lineInfo;
-               int nodeCapacity = 400;
-               int attributeCapacity = 800;
+               int nodeCapacity = 200;
+               int attributeCapacity = 200;
                int nsCapacity = 10;
 
                // Linked Node
-               DTMXPathLinkedNode [] nodes = new DTMXPathLinkedNode [0];
+               DTMXPathLinkedNode [] nodes;
 
                // Attribute
-               DTMXPathAttributeNode [] attributes = new DTMXPathAttributeNode [0];
+               DTMXPathAttributeNode [] attributes;
 
                // NamespaceNode
-               DTMXPathNamespaceNode [] namespaces = new DTMXPathNamespaceNode [0];
+               DTMXPathNamespaceNode [] namespaces;
 
                // idTable [string value] -> int nodeId
                Hashtable idTable;
@@ -79,7 +86,13 @@ namespace Mono.Xml.XPath
                int nodeIndex;
                int attributeIndex;
                int nsIndex;
-               bool requireFirstChildFill;
+               int parentForFirstChild;
+
+               // for attribute processing; should be reset per each element.
+               int firstAttributeIndex;
+               int lastNsIndexInCurrent;
+               int attrIndexAtStart;
+               int nsIndexAtStart;
 
                int prevSibling;
                int position;
@@ -98,27 +111,22 @@ namespace Mono.Xml.XPath
 
                public void Compile ()
                {
-                       idTable = new Hashtable ();
-
                        // index 0 is dummy. No node (including Root) is assigned to this index
                        // So that we can easily compare index != 0 instead of index < 0.
                        // (Difference between jnz or jbe in 80x86.)
-                       AddNode (0, 0, 0, 0, 0, 0, XPathNodeType.All, "", false, "", "", "", "", "", 0, 0, 0);
+                       AddNode (0, 0, 0, 0, 0, XPathNodeType.All, "", false, "", "", "", "", "", 0, 0, 0);
                        nodeIndex++;
                        AddAttribute (0, null, null, null, null, null, 0, 0);
-//                     attributes [0].NextAttribute = 0;
-                       AddNsNode (0, null, null);
+                       AddNsNode (0, null, null, 0);
                        nsIndex++;
-//                     nextNsNode_ [0] = 0;
-                       AddNsNode (1, "xml", XmlNamespaces.XML);
-//                     nextNsNode_ [1] = 0;
+                       AddNsNode (1, "xml", XmlNamespaces.XML, 0);
 
                        // add root.
-                       AddNode (0, 0, 0, 0, -1, 0, XPathNodeType.Root, xmlReader.BaseURI, false, "", "", "", "", "", 1, 0, 0);
+                       AddNode (0, 0, 0, -1, 0, XPathNodeType.Root, xmlReader.BaseURI, false, "", "", "", "", "", 1, 0, 0);
 
                        this.nodeIndex = 1;
                        this.lastNsInScope = 1;
-                       this.requireFirstChildFill = true;
+                       this.parentForFirstChild = nodeIndex;
 
                        while (!xmlReader.EOF)
                                Read ();
@@ -137,7 +145,7 @@ namespace Mono.Xml.XPath
                        skipRead = false;
                        int parent = nodeIndex;
 
-                       if (nodes [nodeIndex].Depth >= xmlReader.Depth) {       // not ">=" ? But == worked when with ArrayList...
+                       if (nodes [nodeIndex].Depth >= xmlReader.Depth) {
                                // if not, then current node is parent.
                                while (xmlReader.Depth <= nodes [parent].Depth)
                                        parent = nodes [parent].Parent;
@@ -152,7 +160,7 @@ namespace Mono.Xml.XPath
                        case XmlNodeType.Comment:
                        case XmlNodeType.Text:
                        case XmlNodeType.ProcessingInstruction:
-                               if (requireFirstChildFill)
+                               if (parentForFirstChild >= 0)
                                        prevSibling = 0;
                                else
                                        while (nodes [prevSibling].Depth != xmlReader.Depth)
@@ -164,7 +172,7 @@ namespace Mono.Xml.XPath
 
                                if (prevSibling != 0)
                                        nodes [prevSibling].NextSibling = nodeIndex;
-                               if (requireFirstChildFill)
+                               if (parentForFirstChild >= 0)
                                        nodes [parent].FirstChild = nodeIndex;
                                break;
                        case XmlNodeType.Whitespace:
@@ -173,14 +181,14 @@ namespace Mono.Xml.XPath
                                else
                                        goto default;
                        case XmlNodeType.EndElement:
-                               requireFirstChildFill = false;
+                               parentForFirstChild = -1;
                                return;
                        default:
                                // No operations. Doctype, EntityReference, 
                                return;
                        }
 
-                       requireFirstChildFill = false;  // Might be changed in ProcessElement().
+                       parentForFirstChild = -1;       // Might be changed in ProcessElement().
 
                        string value = null;
                        XPathNodeType nodeType = xmlReader.NodeType == XmlNodeType.Whitespace ?
@@ -198,7 +206,6 @@ namespace Mono.Xml.XPath
                                        skipRead = true;
                                AddNode (parent,
                                        0,
-                                       attributeIndex,
                                        prevSibling,
                                        xmlReader.Depth,
                                        position,
@@ -231,68 +238,43 @@ namespace Mono.Xml.XPath
 
                private void ProcessElement (int parent, int previousSibling, int position)
                {
-                       int firstAttributeIndex = 0;
-                       int lastNsIndexInCurrent = 0;
-
-                       while (namespaces [lastNsInScope].DeclaredElement == previousSibling) {
-                               lastNsInScope = namespaces [lastNsInScope].NextNamespace;
-                       }
+                       WriteStartElement (parent, previousSibling, position);
 
                        // process namespaces and attributes.
                        if (xmlReader.MoveToFirstAttribute ()) {
                                do {
-                                       if (xmlReader.NamespaceURI == XmlNamespaces.XMLNS) {
-                                               // add namespace node.
-                                               nsIndex++;
-
-                                               int nextTmp = lastNsIndexInCurrent == 0 ? nodes [parent].FirstNamespace : lastNsIndexInCurrent;
-
-                                               this.AddNsNode (nodeIndex,
-                                                       (xmlReader.Prefix == null || xmlReader.Prefix == String.Empty) ?
-                                                               "" : xmlReader.LocalName,
-                                                       xmlReader.Value);
-                                               namespaces [nsIndex].NextNamespace = nextTmp;
-                                               lastNsIndexInCurrent = nsIndex;
-                                       } else {
-                                               // add attribute node.
-                                               attributeIndex ++;
-                                               this.AddAttribute (nodeIndex,
-                                                       xmlReader.LocalName,
-                                                       xmlReader.NamespaceURI, 
-                                                       xmlReader.Prefix != null ? xmlReader.Prefix : String.Empty, 
-                                                       xmlReader.Value,
-                                                       null, 
-                                                       lineInfo != null ? lineInfo.LineNumber : 0,
-                                                       lineInfo != null ? lineInfo.LinePosition : 0);
-                                               if (firstAttributeIndex == 0)
-                                                       firstAttributeIndex = attributeIndex;
-                                               else
-                                                       attributes [attributeIndex - 1].NextAttribute = attributeIndex;
-                                               // dummy for "current" attribute.
-                                               attributes [attributeIndex].NextAttribute = 0;
-
-                                               // Identity infoset
-                                               if (validatingReader != null) {
-                                                       XmlSchemaDatatype dt = validatingReader.SchemaType as XmlSchemaDatatype;
-                                                       if (dt == null) {
-                                                               XmlSchemaType xsType = validatingReader.SchemaType as XmlSchemaType;
-                                                               if (xsType != null)
-                                                                       dt = xsType.Datatype;
-                                                       }
-                                                       if (dt != null && dt.TokenizedType == XmlTokenizedType.ID)
-                                                               idTable.Add (xmlReader.Value, nodeIndex);
-                                               }
-                                       }
+                                       string prefix = xmlReader.Prefix;
+                                       string ns = xmlReader.NamespaceURI;
+                                       if (ns == XmlNamespaces.XMLNS)
+                                               ProcessNamespace ((prefix == null || prefix == String.Empty) ? "" : xmlReader.LocalName, xmlReader.Value);
+                                       else
+                                               ProcessAttribute (prefix, xmlReader.LocalName, ns, xmlReader.Value);
+
                                } while (xmlReader.MoveToNextAttribute ());
                                xmlReader.MoveToElement ();
                        }
 
-                       if (lastNsIndexInCurrent > 0)
-                               lastNsInScope = nsIndex;
+                       CloseStartElement ();
+               }
+
+               private void PrepareStartElement (int previousSibling)
+               {
+                       firstAttributeIndex = 0;
+                       lastNsIndexInCurrent = 0;
+                       attrIndexAtStart = attributeIndex;
+                       nsIndexAtStart = nsIndex;
+
+                       while (namespaces [lastNsInScope].DeclaredElement == previousSibling) {
+                               lastNsInScope = namespaces [lastNsInScope].NextNamespace;
+                       }
+               }
+
+               private void WriteStartElement (int parent, int previousSibling, int position)
+               {
+                       PrepareStartElement (previousSibling);
 
                        AddNode (parent,
-                               firstAttributeIndex,
-                               attributeIndex,
+                               0, // dummy:firstAttribute
                                previousSibling,
                                xmlReader.Depth,
                                position,
@@ -307,8 +289,63 @@ namespace Mono.Xml.XPath
                                lastNsInScope,
                                lineInfo != null ? lineInfo.LineNumber : 0,
                                lineInfo != null ? lineInfo.LinePosition : 0);
-                       if (!xmlReader.IsEmptyElement)
-                               requireFirstChildFill = true;
+
+               }
+
+               private void CloseStartElement ()
+               {
+                       if (attrIndexAtStart != attributeIndex)
+                               nodes [nodeIndex].FirstAttribute = attrIndexAtStart + 1;
+                       if (nsIndexAtStart != nsIndex) {
+                               nodes [nodeIndex].FirstNamespace = nsIndex;
+                               lastNsInScope = nsIndex;
+                       }
+
+                       if (!nodes [nodeIndex].IsEmptyElement)
+                               parentForFirstChild = nodeIndex;
+               }
+
+               private void ProcessNamespace (string prefix, string ns)
+               {
+                       nsIndex++;
+
+                       int nextTmp = lastNsIndexInCurrent == 0 ? nodes [nodeIndex].FirstNamespace : lastNsIndexInCurrent;
+
+                       this.AddNsNode (nodeIndex,
+                               prefix,
+                               ns,
+                               nextTmp);
+                       lastNsIndexInCurrent = nsIndex;
+               }
+
+               private void ProcessAttribute (string prefix, string localName, string ns, string value)
+               {
+                       attributeIndex ++;
+
+                       this.AddAttribute (nodeIndex,
+                               localName,
+                               ns, 
+                               prefix != null ? prefix : String.Empty, 
+                               value,
+                               null, 
+                               lineInfo != null ? lineInfo.LineNumber : 0,
+                               lineInfo != null ? lineInfo.LinePosition : 0);
+                       if (firstAttributeIndex == 0)
+                               firstAttributeIndex = attributeIndex;
+                       else
+                               attributes [attributeIndex - 1].NextAttribute = attributeIndex;
+
+                       // Identity infoset
+                       if (validatingReader != null) {
+                               XmlSchemaDatatype dt = validatingReader.SchemaType as XmlSchemaDatatype;
+                               if (dt == null) {
+                                       XmlSchemaType xsType = validatingReader.SchemaType as XmlSchemaType;
+                                       if (xsType != null)
+                                               dt = xsType.Datatype;
+                               }
+                               if (dt != null && dt.TokenizedType == XmlTokenizedType.ID)
+                                       idTable.Add (value, nodeIndex);
+                       }
                }
 
                private void SetNodeArrayLength (int size)
@@ -335,14 +372,16 @@ namespace Mono.Xml.XPath
                }
 
                // Here followings are skipped: firstChild, nextSibling, 
-               public void AddNode (int parent, int firstAttribute, int attributeEnd, int previousSibling, int depth, int position, XPathNodeType nodeType, string baseUri, bool isEmptyElement, string localName, string ns, string prefix, string value, string xmlLang, int namespaceNode, int lineNumber, int linePosition)
+               public void AddNode (int parent, int firstAttribute, int previousSibling, int depth, int position, XPathNodeType nodeType, string baseUri, bool isEmptyElement, string localName, string ns, string prefix, string value, string xmlLang, int namespaceNode, int lineNumber, int linePosition)
                {
                        if (nodes.Length < nodeIndex + 1) {
-                               nodeCapacity *= 2;
+                               nodeCapacity *= 4;
                                SetNodeArrayLength (nodeCapacity);
                        }
 
-                       DTMXPathLinkedNode curNode = nodes [nodeIndex];
+#if DTM_CLASS
+                       nodes [nodeIndex] = new DTMXPathLinkedNode ();
+#endif
                        nodes [nodeIndex].FirstChild = 0;               // dummy
                        nodes [nodeIndex].Parent = parent;
                        nodes [nodeIndex].FirstAttribute = firstAttribute;
@@ -367,11 +406,13 @@ namespace Mono.Xml.XPath
                public void AddAttribute (int ownerElement, string localName, string ns, string prefix, string value, object schemaType, int lineNumber, int linePosition)
                {
                        if (attributes.Length < attributeIndex + 1) {
-                               attributeCapacity *= 2;
+                               attributeCapacity *= 4;
                                SetAttributeArrayLength (attributeCapacity);
                        }
 
-                       DTMXPathAttributeNode attr = attributes [attributeIndex];
+#if DTM_CLASS
+                       attributes [attributeIndex] = new DTMXPathAttributeNode ();
+#endif
                        attributes [attributeIndex].OwnerElement = ownerElement;
                        attributes [attributeIndex].LocalName = localName;
                        attributes [attributeIndex].NamespaceURI = ns;
@@ -383,17 +424,20 @@ namespace Mono.Xml.XPath
                }
 
                // Followings are skipped: nextNsNode (may be next attribute in the same element, or ancestors' nsNode)
-               public void AddNsNode (int declaredElement, string name, string ns)
+               public void AddNsNode (int declaredElement, string name, string ns, int nextNs)
                {
                        if (namespaces.Length < nsIndex + 1) {
-                               nsCapacity *= 2;
+                               nsCapacity *= 4;
                                SetNsArrayLength (nsCapacity);
                        }
 
-                       DTMXPathNamespaceNode nsNode = namespaces [nsIndex];
+#if DTM_CLASS
+                       namespaces [nsIndex] = new DTMXPathNamespaceNode ();
+#endif
                        namespaces [nsIndex].DeclaredElement = declaredElement;
                        namespaces [nsIndex].Name = name;
                        namespaces [nsIndex].Namespace = ns;
+                       namespaces [nsIndex].NextNamespace = nextNs;
                }
        }
 }
diff --git a/mcs/class/System.XML/Mono.Xml.XPath/DTMXPathDocumentWriter.cs b/mcs/class/System.XML/Mono.Xml.XPath/DTMXPathDocumentWriter.cs
new file mode 100755 (executable)
index 0000000..e952aba
--- /dev/null
@@ -0,0 +1,664 @@
+//
+// Mono.Xml.XPath.DTMXPathDocumentWriter
+//
+// Author:
+//     Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
+//
+// (C) 2003 Atsushi Enomoto
+//
+using System;
+using System.Collections;
+using System.IO;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.XPath;
+
+namespace Mono.Xml.XPath
+{
+       public class DTMXPathDocumentWriter : XmlWriter
+       {
+               public DTMXPathDocumentWriter (XmlNameTable nt, int defaultCapacity)
+               {
+                       nameTable = nt == null ? new NameTable () : nt;
+                       nodeCapacity = defaultCapacity;
+                       attributeCapacity = nodeCapacity;
+                       idTable = new Hashtable ();
+
+                       nodes = new DTMXPathLinkedNode [nodeCapacity];
+                       attributes = new DTMXPathAttributeNode [attributeCapacity];
+                       namespaces = new DTMXPathNamespaceNode [0];
+
+                       Init ();
+               }
+               
+               XmlNameTable nameTable;
+               int nodeCapacity = 200;
+               int attributeCapacity = 200;
+               int nsCapacity = 10;
+
+               // Linked Node
+               DTMXPathLinkedNode [] nodes;
+
+               // Attribute
+               DTMXPathAttributeNode [] attributes;
+
+               // NamespaceNode
+               DTMXPathNamespaceNode [] namespaces;
+
+               // idTable [string value] -> int nodeId
+               Hashtable idTable;
+
+               int nodeIndex;
+               int attributeIndex;
+               int nsIndex;
+               int parentForFirstChild;
+
+               // for attribute processing; should be reset per each element.
+               int firstAttributeIndex;
+               int lastNsIndexInCurrent;
+               int attrIndexAtStart;
+               int nsIndexAtStart;
+
+               int prevSibling;
+               int position;
+               int lastNsInScope;
+               bool skipRead = false;
+
+               // They are only used in Writer
+               int writerDepth;
+               WriteState state;
+               bool openNamespace;
+
+               public DTMXPathDocument CreateDocument ()
+               {
+                       return new DTMXPathDocument (nameTable,
+                               nodes,
+                               attributes,
+                               namespaces,
+                               idTable
+                       );
+               }
+
+               public void Init ()
+               {
+                       // index 0 is dummy. No node (including Root) is assigned to this index
+                       // So that we can easily compare index != 0 instead of index < 0.
+                       // (Difference between jnz or jbe in 80x86.)
+                       AddNode (0, 0, 0, 0, 0, XPathNodeType.All, "", false, "", "", "", "", "", 0, 0, 0);
+                       nodeIndex++;
+                       AddAttribute (0, null, null, null, null, null, 0, 0);
+                       AddNsNode (0, null, null, 0);
+                       nsIndex++;
+                       AddNsNode (1, "xml", XmlNamespaces.XML, 0);
+
+                       // add root.
+                       AddNode (0, 0, 0, -1, 0, XPathNodeType.Root, null, false, "", "", "", "", "", 1, 0, 0);
+
+                       this.nodeIndex = 1;
+                       this.lastNsInScope = 1;
+                       this.parentForFirstChild = nodeIndex;
+
+                       state = WriteState.Content;
+               }
+
+               private int GetParentIndex ()
+               {
+                       if (parentForFirstChild >= 0)
+                               return parentForFirstChild;
+
+                       int parent = nodeIndex;
+                       if (nodes [nodeIndex].Depth >= writerDepth) {
+                               // if not, then current node is parent.
+                               while (writerDepth <= nodes [parent].Depth)
+                                       parent = nodes [parent].Parent;
+                       }
+                       return parent;
+               }
+
+               private int GetPreviousSiblingIndex ()
+               {
+                       int prevSibling = nodeIndex;
+                       if (parentForFirstChild >= 0)
+                               prevSibling = 0;
+                       else
+                               while (nodes [prevSibling].Depth != writerDepth)
+                                       prevSibling = nodes [prevSibling].Parent;
+                       return prevSibling;
+               }
+
+               private int GetPosition (int prevSibling)
+               {
+                       if (prevSibling != 0)
+                               return nodes [prevSibling].Position + 1;
+                       else
+                               return 0;
+               }
+
+               private void UpdateTreeForAddition ()
+               {
+                       int parent = GetParentIndex ();
+                       prevSibling = GetPreviousSiblingIndex ();
+                       position = GetPosition (prevSibling);
+
+                       nodeIndex++;
+
+                       if (prevSibling != 0)
+                               nodes [prevSibling].NextSibling = nodeIndex;
+                       if (parentForFirstChild >= 0)
+                               nodes [parent].FirstChild = nodeIndex;
+
+                       parentForFirstChild = -1;
+               }
+
+               private void CloseStartElement ()
+               {
+                       if (attrIndexAtStart != attributeIndex)
+                               nodes [nodeIndex].FirstAttribute = attrIndexAtStart + 1;
+                       if (nsIndexAtStart != nsIndex) {
+                               nodes [nodeIndex].FirstNamespace = nsIndex;
+                               lastNsInScope = nsIndex;
+                       }
+
+                       if (!nodes [nodeIndex].IsEmptyElement)
+                               parentForFirstChild = nodeIndex;
+\r
+                       state = WriteState.Content;\r
+                       writerDepth++;
+               }
+
+               #region Adding Nodes
+               private void SetNodeArrayLength (int size)
+               {
+                       DTMXPathLinkedNode [] newArr = new DTMXPathLinkedNode [size];
+                       Array.Copy (nodes, newArr, System.Math.Min (size, nodes.Length));
+                       nodes = newArr;
+               }
+
+               private void SetAttributeArrayLength (int size)
+               {
+                       DTMXPathAttributeNode [] newArr = 
+                               new DTMXPathAttributeNode [size];
+                       Array.Copy (attributes, newArr, System.Math.Min (size, attributes.Length));
+                       attributes = newArr;
+               }
+
+               private void SetNsArrayLength (int size)
+               {
+                       DTMXPathNamespaceNode [] newArr =
+                               new DTMXPathNamespaceNode [size];
+                       Array.Copy (namespaces, newArr, System.Math.Min (size, namespaces.Length));
+                       namespaces = newArr;
+               }
+
+               // Here followings are skipped: firstChild, nextSibling, 
+               public void AddNode (int parent, int firstAttribute, int previousSibling, int depth, int position, XPathNodeType nodeType, string baseUri, bool isEmptyElement, string localName, string ns, string prefix, string value, string xmlLang, int namespaceNode, int lineNumber, int linePosition)
+               {
+                       if (nodes.Length < nodeIndex + 1) {
+                               nodeCapacity *= 4;
+                               SetNodeArrayLength (nodeCapacity);
+                       }
+
+#if DTM_CLASS
+                       nodes [nodeIndex] = new DTMXPathLinkedNode ();
+#endif
+                       nodes [nodeIndex].FirstChild = 0;               // dummy
+                       nodes [nodeIndex].Parent = parent;
+                       nodes [nodeIndex].FirstAttribute = firstAttribute;
+                       nodes [nodeIndex].PreviousSibling = previousSibling;
+                       nodes [nodeIndex].NextSibling = 0;      // dummy
+                       nodes [nodeIndex].Depth = depth;
+                       nodes [nodeIndex].Position = position;
+                       nodes [nodeIndex].NodeType = nodeType;
+                       nodes [nodeIndex].BaseURI = baseUri;
+                       nodes [nodeIndex].IsEmptyElement = isEmptyElement;
+                       nodes [nodeIndex].LocalName = localName;
+                       nodes [nodeIndex].NamespaceURI = ns;
+                       nodes [nodeIndex].Prefix = prefix;
+                       nodes [nodeIndex].Value = value;
+                       nodes [nodeIndex].XmlLang = xmlLang;
+                       nodes [nodeIndex].FirstNamespace = namespaceNode;
+                       nodes [nodeIndex].LineNumber = lineNumber;
+                       nodes [nodeIndex].LinePosition = linePosition;
+               }
+
+               // Followings are skipped: nextAttribute,
+               public void AddAttribute (int ownerElement, string localName, string ns, string prefix, string value, object schemaType, int lineNumber, int linePosition)
+               {
+                       if (attributes.Length < attributeIndex + 1) {
+                               attributeCapacity *= 4;
+                               SetAttributeArrayLength (attributeCapacity);
+                       }
+
+#if DTM_CLASS
+                       attributes [attributeIndex] = new DTMXPathAttributeNode ();
+#endif
+                       attributes [attributeIndex].OwnerElement = ownerElement;
+                       attributes [attributeIndex].LocalName = localName;
+                       attributes [attributeIndex].NamespaceURI = ns;
+                       attributes [attributeIndex].Prefix = prefix;
+                       attributes [attributeIndex].Value = value;
+                       attributes [attributeIndex].SchemaType = schemaType;
+                       attributes [attributeIndex].LineNumber = lineNumber;
+                       attributes [attributeIndex].LinePosition = linePosition;
+               }
+
+               // Followings are skipped: nextNsNode (may be next attribute in the same element, or ancestors' nsNode)
+               public void AddNsNode (int declaredElement, string name, string ns, int nextNs)
+               {
+                       if (namespaces.Length < nsIndex + 1) {
+                               nsCapacity *= 4;
+                               SetNsArrayLength (nsCapacity);
+                       }
+
+#if DTM_CLASS
+                       namespaces [nsIndex] = new DTMXPathNamespaceNode ();
+#endif
+                       namespaces [nsIndex].DeclaredElement = declaredElement;
+                       namespaces [nsIndex].Name = name;
+                       namespaces [nsIndex].Namespace = ns;
+                       namespaces [nsIndex].NextNamespace = nextNs;
+               }
+               #endregion
+
+               #region XmlWriter methods
+               // They are not supported
+               public override string XmlLang { get { return null; } }
+               public override XmlSpace XmlSpace { get { return XmlSpace.None; } }
+
+               public override WriteState WriteState { get { return state; } }
+
+               public override void Close ()
+               {
+                       // Fixup arrays
+                       SetNodeArrayLength (nodeIndex + 1);
+                       SetAttributeArrayLength (attributeIndex + 1);
+                       SetNsArrayLength (nsIndex + 1);
+               }
+
+               public override void Flush ()
+               {
+                       // do nothing
+               }
+
+               public override string LookupPrefix (string ns)
+               {
+                       int tmp = nsIndex;
+                       while (tmp != 0) {
+                               if (namespaces [tmp].Namespace == ns)
+                                       return namespaces [tmp].Name;
+                               tmp = namespaces [tmp].NextNamespace;
+                       }
+                       return null;
+               }
+\r
+               public override void WriteCData (string data)\r
+               {\r
+                       AddTextNode (data);\r
+               }\r
+\r
+               private void AddTextNode (string data)\r
+               {\r
+                       switch (state) {\r
+                       case WriteState.Element:\r
+                               CloseStartElement ();\r
+                               break;\r
+                       case WriteState.Content:\r
+                               break;\r
+                       default:\r
+                               throw new InvalidOperationException ("Invalid document state for CDATA section: " + state);\r
+                       }\r
+\r
+                       // When text after text, just add the value, and return.\r
+                       if (nodes [nodeIndex].Depth == writerDepth) {\r
+                               switch (nodes [nodeIndex].NodeType) {\r
+                               case XPathNodeType.Text:\r
+                               case XPathNodeType.SignificantWhitespace:\r
+                                       nodes [nodeIndex].Value += data;\r
+                                       if (XmlChar.IsWhitespace (data))\r
+                                               nodes [nodeIndex].NodeType = XPathNodeType.SignificantWhitespace;\r
+                                       else\r
+                                               nodes [nodeIndex].NodeType = XPathNodeType.Text;\r
+                                       return;\r
+                               }\r
+                       }\r
+\r
+                       int parent = GetParentIndex ();\r
+                       UpdateTreeForAddition ();\r
+
+                       AddNode (parent,
+                               0, // attribute
+                               prevSibling,
+                               writerDepth,
+                               position,
+                               XPathNodeType.Text,
+                               null,
+                               false,
+                               null,
+                               String.Empty,
+                               String.Empty,
+                               data,
+                               null,
+                               0, // nsIndex
+                               0, // line info
+                               0);
+               }\r
+\r
+               private void CheckTopLevelNode ()\r
+               {\r
+                       switch (state) {\r
+                       case WriteState.Element:\r
+                               CloseStartElement ();\r
+                               break;\r
+                       case WriteState.Content:\r
+                       case WriteState.Prolog:\r
+                       case WriteState.Start:\r
+                               break;\r
+                       default:\r
+                               throw new InvalidOperationException ("Invalid document state for CDATA section: " + state);\r
+                       }\r
+               }\r
+\r
+               public override void WriteComment (string data)\r
+               {\r
+                       CheckTopLevelNode ();\r
+\r
+                       int parent = GetParentIndex ();\r
+                       UpdateTreeForAddition ();\r
+
+                       AddNode (parent,
+                               0, // attribute
+                               prevSibling,
+                               writerDepth,
+                               position,
+                               XPathNodeType.Comment,
+                               null,
+                               false,
+                               null,
+                               String.Empty,
+                               String.Empty,
+                               data,
+                               null,
+                               0, // nsIndex
+                               0, // line info
+                               0);
+               }\r
+\r
+               public override void WriteProcessingInstruction (string name, string data)\r
+               {\r
+                       CheckTopLevelNode ();\r
+\r
+                       int parent = GetParentIndex ();\r
+                       UpdateTreeForAddition ();\r
+
+                       AddNode (parent,
+                               0, // attribute
+                               prevSibling,
+                               writerDepth,
+                               position,
+                               XPathNodeType.ProcessingInstruction,
+                               null,
+                               false,
+                               name,
+                               String.Empty,
+                               String.Empty,
+                               data,
+                               null,
+                               0, // nsIndex
+                               0, // line info
+                               0);
+               }\r
+\r
+               public override void WriteWhitespace (string data)\r
+               {\r
+                       CheckTopLevelNode ();\r
+\r
+                       int parent = GetParentIndex ();\r
+                       UpdateTreeForAddition ();\r
+
+                       AddNode (parent,
+                               0, // attribute
+                               prevSibling,
+                               writerDepth,
+                               position,
+                               XPathNodeType.Whitespace,
+                               null,
+                               false,
+                               null,
+                               String.Empty,
+                               String.Empty,
+                               data,
+                               null,
+                               0, // nsIndex
+                               0, // line info
+                               0);
+               }\r
+\r
+               public override void WriteStartDocument ()\r
+               {\r
+                       // do nothing\r
+               }\r
+\r
+               public override void WriteStartDocument (bool standalone)\r
+               {\r
+                       // do nothing\r
+               }\r
+\r
+               public override void WriteEndDocument ()\r
+               {\r
+                       // do nothing\r
+               }\r
+\r
+               public override void WriteStartElement (string prefix, string localName, string ns)\r
+               {\r
+                       switch (state) {\r
+                       case WriteState.Element:\r
+                               CloseStartElement ();\r
+                               break;\r
+                       case WriteState.Start:\r
+                       case WriteState.Prolog:\r
+                       case WriteState.Content:\r
+                               break;\r
+                       default:\r
+                               throw new InvalidOperationException ("Invalid document state for writing element: " + state);\r
+                       }\r
+\r
+                       int parent = GetParentIndex ();\r
+                       UpdateTreeForAddition ();\r
+
+                       WriteStartElement (parent, prevSibling, position, prefix, localName, ns);
+                       state = WriteState.Element;
+               }\r
+
+               private void WriteStartElement (int parent, int previousSibling, int position, string prefix, string localName, string ns)
+               {
+                       PrepareStartElement (previousSibling);
+
+                       AddNode (parent,
+                               0, // dummy:firstAttribute
+                               previousSibling,
+                               writerDepth,
+                               position,
+                               XPathNodeType.Element,
+                               null,
+                               false,
+                               localName,
+                               ns,
+                               prefix,
+                               "",     // Element has no internal value.
+                               null,
+                               lastNsInScope,
+                               0,
+                               0);
+               }
+
+               private void PrepareStartElement (int previousSibling)
+               {
+                       firstAttributeIndex = 0;
+                       lastNsIndexInCurrent = 0;
+                       attrIndexAtStart = attributeIndex;
+                       nsIndexAtStart = nsIndex;
+
+                       while (namespaces [lastNsInScope].DeclaredElement == previousSibling) {
+                               lastNsInScope = namespaces [lastNsInScope].NextNamespace;
+                       }
+               }
+\r
+               public override void WriteEndElement ()\r
+               {\r
+                       WriteEndElement (false);\r
+               }\r
+\r
+               public override void WriteFullEndElement ()\r
+               {\r
+                       WriteEndElement (true);\r
+               }\r
+\r
+               private void WriteEndElement (bool full)\r
+               {\r
+                       switch (state) {\r
+                       case WriteState.Element:\r
+                               CloseStartElement ();\r
+                               break;\r
+                       case WriteState.Content:\r
+                               break;\r
+                       default:\r
+                               throw new InvalidOperationException ("Invalid state for writing EndElement: " + state);\r
+                       }\r
+                       parentForFirstChild = -1;\r
+                       if (nodes [nodeIndex].NodeType == XPathNodeType.Element) {\r
+                               if (!full)\r
+                                       nodes [nodeIndex].IsEmptyElement = true;\r
+                       }\r
+\r
+                       writerDepth--;\r
+               }\r
+\r
+               public override void WriteStartAttribute (string prefix, string localName, string ns)\r
+               {\r
+                       if (state != WriteState.Element)\r
+                               throw new InvalidOperationException ("Invalid document state for attribute: " + state);\r
+\r
+                       state = WriteState.Attribute;\r
+                       if (ns == XmlNamespaces.XMLNS)
+                               ProcessNamespace ((prefix == null || prefix == String.Empty) ? "" : localName, String.Empty); // dummy: Value should be completed
+                       else
+                               ProcessAttribute (prefix, localName, ns, String.Empty); // dummy: Value should be completed
+               }\r
+\r
+               private void ProcessNamespace (string prefix, string ns)
+               {
+                       nsIndex++;
+
+                       int nextTmp = lastNsIndexInCurrent == 0 ? nodes [nodeIndex].FirstNamespace : lastNsIndexInCurrent;
+
+                       this.AddNsNode (nodeIndex,
+                               prefix,
+                               ns,
+                               nextTmp);
+                       lastNsIndexInCurrent = nsIndex;
+                       openNamespace = true;
+               }
+
+               private void ProcessAttribute (string prefix, string localName, string ns, string value)
+               {
+                       attributeIndex ++;
+
+                       this.AddAttribute (nodeIndex,
+                               localName,
+                               ns, 
+                               prefix != null ? prefix : String.Empty, 
+                               value,
+                               null,
+                               0,
+                               0);
+                       if (firstAttributeIndex == 0)
+                               firstAttributeIndex = attributeIndex;
+                       else
+                               attributes [attributeIndex - 1].NextAttribute = attributeIndex;
+               }
+
+               public override void WriteEndAttribute ()\r
+               {\r
+                       if (state != WriteState.Attribute)\r
+                               throw new InvalidOperationException ();\r
+\r
+                       openNamespace = false;\r
+                       state = WriteState.Element;\r
+               }\r
+\r
+               public override void WriteString (string text)\r
+               {\r
+                       if (WriteState == WriteState.Attribute) {\r
+                               if (openNamespace)\r
+                                       namespaces [nsIndex].Namespace += text;\r
+                               else\r
+                                       attributes [attributeIndex].Value += text;\r
+                       }\r
+                       else\r
+                               AddTextNode (text);\r
+               }\r
+\r
+               // Well, they cannot be supported, but actually used to\r
+               // disable-output-escaping = "true"\r
+               public override void WriteRaw (string data)\r
+               {\r
+                       WriteString (data);\r
+               }\r
+
+               public override void WriteRaw (char [] data, int start, int len)\r
+               {\r
+                       WriteString (new string (data, start, len));\r
+               }\r
+\r
+               public override void WriteName (string name)\r
+               {\r
+                       WriteString (name);\r
+               }\r
+\r
+               public override void WriteNmToken (string name)\r
+               {\r
+                       WriteString (name);\r
+               }\r
+\r
+               public override void WriteBase64 (byte [] buffer, int index, int count)\r
+               {\r
+                       throw new NotSupportedException ();\r
+               }
+
+               public override void WriteBinHex (byte [] buffer, int index, int count)\r
+               {\r
+                       throw new NotSupportedException ();\r
+               }\r
+\r
+               public override void WriteChars (char [] buffer, int index, int count)\r
+               {\r
+                       throw new NotSupportedException ();\r
+               }\r
+\r
+               public override void WriteCharEntity (char c)\r
+               {\r
+                       throw new NotSupportedException ();\r
+               }\r
+\r
+               public override void WriteDocType (string name, string pub, string sys, string intSubset)\r
+               {\r
+                       throw new NotSupportedException ();\r
+               }\r
+
+               public override void WriteEntityRef (string name)
+               {
+                       throw new NotSupportedException ();\r
+               }
+
+               public override void WriteQualifiedName (string localName, string ns)\r
+               {\r
+                       throw new NotSupportedException ();\r
+               }\r
+\r
+               public override void WriteSurrogateCharEntity (char high, char low)\r
+               {\r
+                       throw new NotSupportedException ();\r
+               }\r
+               #endregion
+       }
+}
index 638eaed6c7f74547e3ff63c60f4d3525e583685b..7db6bbf9c1543213f0bcaca6fbdb61388fbbd83f 100644 (file)
@@ -8,13 +8,18 @@
 //
 // These classes represent each node of DTMXPathNavigator.
 //
+//#define DTM_CLASS
 
 using System;
 using System.Xml.XPath;
 
 namespace Mono.Xml.XPath
 {
+#if DTM_CLASS
+       public class DTMXPathLinkedNode
+#else
        public struct DTMXPathLinkedNode
+#endif
        {
                public int FirstChild;
                public int Parent;
@@ -36,7 +41,11 @@ namespace Mono.Xml.XPath
                public int LinePosition;
        }
 
+#if DTM_CLASS
+       public class DTMXPathAttributeNode
+#else
        public struct DTMXPathAttributeNode
+#endif
        {
                public int OwnerElement;
                public int NextAttribute;
@@ -49,7 +58,11 @@ namespace Mono.Xml.XPath
                public int LinePosition;
        }
 
+#if DTM_CLASS
+       public class DTMXPathNamespaceNode
+#else
        public struct DTMXPathNamespaceNode
+#endif
        {
                public int DeclaredElement;
                public int NextNamespace;