Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtsushi Eno <atsushieno@gmail.com>2004-10-22 21:49:46 +0400
committerAtsushi Eno <atsushieno@gmail.com>2004-10-22 21:49:46 +0400
commit05009bb9af0404c3efb0e980850bccec466da6c1 (patch)
treeaea0481e9ec59dc4205f3d135a5d5e4883aa5ba7 /mcs/class/Mono.Xml.Ext
parent1d2d816b044950f8e21db587d052841cfac65336 (diff)
2004-10-22 Atsushi Enomoto <atsushi@ximian.com>
DTMXPathDocument.cs, DTMXPathDocumentBuilder.cs, DTMXPathDocumentWriter.cs, DTMXPathNavigator.cs, DTMXPathNode.cs, XPathEditableDocument.cs: Initial Checkin (it is not compiled as yet). svn path=/trunk/mcs/; revision=35255
Diffstat (limited to 'mcs/class/Mono.Xml.Ext')
-rwxr-xr-xmcs/class/Mono.Xml.Ext/Mono.Xml.XPath/ChangeLog9
-rwxr-xr-xmcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocument.cs97
-rwxr-xr-xmcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentBuilder.cs475
-rwxr-xr-xmcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentWriter.cs689
-rwxr-xr-xmcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs630
-rwxr-xr-xmcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNode.cs107
-rwxr-xr-xmcs/class/Mono.Xml.Ext/Mono.Xml.XPath/XPathEditableDocument.cs765
7 files changed, 2772 insertions, 0 deletions
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/ChangeLog b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/ChangeLog
new file mode 100755
index 00000000000..596b2e9a6c5
--- /dev/null
+++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/ChangeLog
@@ -0,0 +1,9 @@
+2004-10-22 Atsushi Enomoto <atsushi@ximian.com>
+
+ DTMXPathDocument.cs,
+ DTMXPathDocumentBuilder.cs,
+ DTMXPathDocumentWriter.cs,
+ DTMXPathNavigator.cs,
+ DTMXPathNode.cs,
+ XPathEditableDocument.cs: Initial Checkin (it is not compiled as yet).
+
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocument.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocument.cs
new file mode 100755
index 00000000000..d7b2911e1ca
--- /dev/null
+++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocument.cs
@@ -0,0 +1,97 @@
+//
+// Mono.Xml.XPath.DTMXPathDocument
+//
+// Author:
+// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
+//
+// (C) 2003 Atsushi Enomoto
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace Mono.Xml.XPath
+{
+#if OUTSIDE_SYSTEM_XML
+ public
+#else
+ internal
+#endif
+ class DTMXPathDocument : IXPathNavigable
+ {
+
+#region ctor.
+
+ public DTMXPathDocument (XmlNameTable nameTable,
+ DTMXPathLinkedNode [] nodes,
+ DTMXPathAttributeNode [] attributes,
+ DTMXPathNamespaceNode [] namespaces,
+ Hashtable idTable)
+ {
+ this.nameTable = nameTable;
+ this.nodes = nodes;
+ this.attributes = attributes;
+ this.namespaces = namespaces;
+ this.idTable = idTable;
+ }
+
+#endregion
+
+
+#region Methods
+ public XPathNavigator CreateNavigator ()
+ {
+ if (root == null) {
+ root = new DTMXPathNavigator (this,
+ nameTable,
+ nodes,
+ attributes,
+ namespaces,
+ idTable);
+ }
+ return root.Clone ();
+ }
+
+#endregion
+
+ XmlNameTable nameTable;
+
+ // Root XPathNavigator.
+ DTMXPathNavigator root;
+
+#region Immutable tree fields
+
+ DTMXPathLinkedNode [] nodes = new DTMXPathLinkedNode [0];
+ DTMXPathAttributeNode [] attributes = new DTMXPathAttributeNode [0];
+ DTMXPathNamespaceNode [] namespaces = new DTMXPathNamespaceNode [0];
+
+ // idTable [string value] -> int nodeId
+ readonly Hashtable idTable;
+
+#endregion
+
+ }
+}
+
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentBuilder.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentBuilder.cs
new file mode 100755
index 00000000000..953bd58ac04
--- /dev/null
+++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentBuilder.cs
@@ -0,0 +1,475 @@
+//
+// Mono.Xml.XPath.DTMXPathDocumentBuilder
+//
+// Author:
+// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
+//
+// (C) 2003 Atsushi Enomoto
+//
+//#define DTM_CLASS
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections;
+using System.IO;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.XPath;
+
+namespace Mono.Xml.XPath
+{
+
+#if OUTSIDE_SYSTEM_XML
+ public
+#else
+ internal
+#endif
+ class DTMXPathDocumentBuilder
+ {
+ public DTMXPathDocumentBuilder (string url)
+ : this (url, XmlSpace.None, 200)
+ {
+ }
+
+ public DTMXPathDocumentBuilder (string url, XmlSpace space)
+ : this (url, space, 200)
+ {
+ }
+
+ public DTMXPathDocumentBuilder (string url, XmlSpace space, int defaultCapacity)
+ {
+ XmlReader r = null;
+ try {
+ r = new XmlTextReader (url);
+ Init (r, space, defaultCapacity);
+ } finally {
+ if (r != null)
+ r.Close ();
+ }
+ }
+
+ public DTMXPathDocumentBuilder (XmlReader reader)
+ : this (reader, XmlSpace.None, 200)
+ {
+ }
+
+ public DTMXPathDocumentBuilder (XmlReader reader, XmlSpace space)
+ : this (reader, space, 200)
+ {
+ }
+
+ public DTMXPathDocumentBuilder (XmlReader reader, XmlSpace space, int defaultCapacity)
+ {
+ Init (reader, space, defaultCapacity);
+ }
+
+ private void Init (XmlReader reader, XmlSpace space, int defaultCapacity)
+ {
+ this.xmlReader = reader;
+ this.validatingReader = reader as XmlValidatingReader;
+ lineInfo = reader as IXmlLineInfo;
+ this.xmlSpace = space;
+ this.nameTable = reader.NameTable;
+ nodeCapacity = defaultCapacity;
+ attributeCapacity = nodeCapacity;
+ idTable = new Hashtable ();
+
+ nodes = new DTMXPathLinkedNode [nodeCapacity];
+ attributes = new DTMXPathAttributeNode [attributeCapacity];
+ namespaces = new DTMXPathNamespaceNode [0];
+
+ Compile ();
+ }
+
+ XmlReader xmlReader;
+ XmlValidatingReader validatingReader;
+ XmlSpace xmlSpace;
+ XmlNameTable nameTable;
+ IXmlLineInfo lineInfo;
+ 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 lastNsInScope;
+ bool skipRead = false;
+
+ public DTMXPathDocument CreateDocument ()
+ {
+ return new DTMXPathDocument (nameTable,
+ nodes,
+ attributes,
+ namespaces,
+ idTable
+ );
+ }
+
+ public void Compile ()
+ {
+ // 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, 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, XPathNodeType.Root, xmlReader.BaseURI, false, "", "", "", "", "", 1, 0, 0);
+
+ this.nodeIndex = 1;
+ this.lastNsInScope = 1;
+ this.parentForFirstChild = nodeIndex;
+
+ while (!xmlReader.EOF)
+ Read ();
+ SetNodeArrayLength (nodeIndex + 1);
+ SetAttributeArrayLength (attributeIndex + 1);
+ SetNsArrayLength (nsIndex + 1);
+
+ xmlReader = null; // It is no more required.
+ }
+
+ public void Read ()
+ {
+ if (!skipRead)
+ if (!xmlReader.Read ())
+ return;
+ skipRead = false;
+ int parent = nodeIndex;
+
+ if (nodes [nodeIndex].Depth >= xmlReader.Depth) {
+ // if not, then current node is parent.
+ while (xmlReader.Depth <= nodes [parent].Depth)
+ parent = nodes [parent].Parent;
+ }
+
+ prevSibling = nodeIndex;
+ switch (xmlReader.NodeType) {
+ case XmlNodeType.Element:
+ case XmlNodeType.CDATA:
+ case XmlNodeType.SignificantWhitespace:
+ case XmlNodeType.Comment:
+ case XmlNodeType.Text:
+ case XmlNodeType.ProcessingInstruction:
+ if (parentForFirstChild >= 0)
+ prevSibling = 0;
+ else
+ while (nodes [prevSibling].Depth != xmlReader.Depth)
+ prevSibling = nodes [prevSibling].Parent;
+
+ nodeIndex++;
+
+ if (prevSibling != 0)
+ nodes [prevSibling].NextSibling = nodeIndex;
+ if (parentForFirstChild >= 0)
+ nodes [parent].FirstChild = nodeIndex;
+ break;
+ case XmlNodeType.Whitespace:
+ if (xmlSpace == XmlSpace.Preserve)
+ goto case XmlNodeType.Text;
+ else
+ goto default;
+ case XmlNodeType.EndElement:
+ parentForFirstChild = -1;
+ return;
+ default:
+ // No operations. Doctype, EntityReference,
+ return;
+ }
+
+ parentForFirstChild = -1; // Might be changed in ProcessElement().
+
+ string value = null;
+ XPathNodeType nodeType = xmlReader.NodeType == XmlNodeType.Whitespace ?
+ XPathNodeType.Whitespace : XPathNodeType.Text;
+
+ switch (xmlReader.NodeType) {
+ case XmlNodeType.Element:
+ ProcessElement (parent, prevSibling);
+ break;
+ case XmlNodeType.CDATA:
+ case XmlNodeType.SignificantWhitespace:
+ case XmlNodeType.Text:
+ case XmlNodeType.Whitespace:
+ if (value == null)
+ skipRead = true;
+ AddNode (parent,
+ 0,
+ prevSibling,
+ xmlReader.Depth,
+ nodeType,
+ xmlReader.BaseURI,
+ xmlReader.IsEmptyElement,
+ xmlReader.LocalName, // for PI
+ xmlReader.NamespaceURI, // for PI
+ xmlReader.Prefix,
+ value,
+ xmlReader.XmlLang,
+ nsIndex,
+ lineInfo != null ? lineInfo.LineNumber : 0,
+ lineInfo != null ? lineInfo.LinePosition : 0);
+ // this code is tricky, but after ReadString() invokation,
+ // xmlReader is moved to next node!!
+ if (value == null)
+ nodes [nodeIndex].Value = xmlReader.ReadString ();
+ break;
+ case XmlNodeType.Comment:
+ value = xmlReader.Value;
+ nodeType = XPathNodeType.Comment;
+ goto case XmlNodeType.Text;
+ case XmlNodeType.ProcessingInstruction:
+ value = xmlReader.Value;
+ nodeType = XPathNodeType.ProcessingInstruction;
+ goto case XmlNodeType.Text;
+ }
+ }
+
+ private void ProcessElement (int parent, int previousSibling)
+ {
+ WriteStartElement (parent, previousSibling);
+
+ // process namespaces and attributes.
+ if (xmlReader.MoveToFirstAttribute ()) {
+ do {
+ 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 ();
+ }
+
+ 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)
+ {
+ PrepareStartElement (previousSibling);
+
+ AddNode (parent,
+ 0, // dummy:firstAttribute
+ previousSibling,
+ xmlReader.Depth,
+ XPathNodeType.Element,
+ xmlReader.BaseURI,
+ xmlReader.IsEmptyElement,
+ xmlReader.LocalName,
+ xmlReader.NamespaceURI,
+ xmlReader.Prefix,
+ "", // Element has no internal value.
+ xmlReader.XmlLang,
+ lastNsInScope,
+ lineInfo != null ? lineInfo.LineNumber : 0,
+ lineInfo != null ? lineInfo.LinePosition : 0);
+
+ }
+
+ 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)
+ {
+ 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, 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].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;
+ }
+ }
+}
+
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentWriter.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentWriter.cs
new file mode 100755
index 00000000000..0dd7c7849ad
--- /dev/null
+++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathDocumentWriter.cs
@@ -0,0 +1,689 @@
+//
+// Mono.Xml.XPath.DTMXPathDocumentWriter
+//
+// Author:
+// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
+//
+// (C) 2003 Atsushi Enomoto
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections;
+using System.IO;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.XPath;
+
+namespace Mono.Xml.XPath
+{
+#if OUTSIDE_SYSTEM_XML
+ public
+#else
+ internal
+#endif
+ 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 lastNsInScope;
+
+ // 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, 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, 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 void UpdateTreeForAddition ()
+ {
+ int parent = GetParentIndex ();
+ prevSibling = GetPreviousSiblingIndex ();
+
+ 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;
+
+ state = WriteState.Content;
+ 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, 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].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;
+ }
+
+ public override void WriteCData (string data)
+ {
+ AddTextNode (data);
+ }
+
+ private void AddTextNode (string data)
+ {
+ switch (state) {
+ case WriteState.Element:
+ CloseStartElement ();
+ break;
+ case WriteState.Content:
+ break;
+ default:
+ throw new InvalidOperationException ("Invalid document state for CDATA section: " + state);
+ }
+
+ // When text after text, just add the value, and return.
+ if (nodes [nodeIndex].Depth == writerDepth) {
+ switch (nodes [nodeIndex].NodeType) {
+ case XPathNodeType.Text:
+ case XPathNodeType.SignificantWhitespace:
+ nodes [nodeIndex].Value += data;
+ if (IsWhitespace (data))
+ nodes [nodeIndex].NodeType = XPathNodeType.SignificantWhitespace;
+ else
+ nodes [nodeIndex].NodeType = XPathNodeType.Text;
+ return;
+ }
+ }
+
+ int parent = GetParentIndex ();
+ UpdateTreeForAddition ();
+
+ AddNode (parent,
+ 0, // attribute
+ prevSibling,
+ writerDepth,
+ XPathNodeType.Text,
+ null,
+ false,
+ null,
+ String.Empty,
+ String.Empty,
+ data,
+ null,
+ 0, // nsIndex
+ 0, // line info
+ 0);
+ }
+
+ private void CheckTopLevelNode ()
+ {
+ switch (state) {
+ case WriteState.Element:
+ CloseStartElement ();
+ break;
+ case WriteState.Content:
+ case WriteState.Prolog:
+ case WriteState.Start:
+ break;
+ default:
+ throw new InvalidOperationException ("Invalid document state for CDATA section: " + state);
+ }
+ }
+
+ public override void WriteComment (string data)
+ {
+ CheckTopLevelNode ();
+
+ int parent = GetParentIndex ();
+ UpdateTreeForAddition ();
+
+ AddNode (parent,
+ 0, // attribute
+ prevSibling,
+ writerDepth,
+ XPathNodeType.Comment,
+ null,
+ false,
+ null,
+ String.Empty,
+ String.Empty,
+ data,
+ null,
+ 0, // nsIndex
+ 0, // line info
+ 0);
+ }
+
+ public override void WriteProcessingInstruction (string name, string data)
+ {
+ CheckTopLevelNode ();
+
+ int parent = GetParentIndex ();
+ UpdateTreeForAddition ();
+
+ AddNode (parent,
+ 0, // attribute
+ prevSibling,
+ writerDepth,
+ XPathNodeType.ProcessingInstruction,
+ null,
+ false,
+ name,
+ String.Empty,
+ String.Empty,
+ data,
+ null,
+ 0, // nsIndex
+ 0, // line info
+ 0);
+ }
+
+ public override void WriteWhitespace (string data)
+ {
+ CheckTopLevelNode ();
+
+ int parent = GetParentIndex ();
+ UpdateTreeForAddition ();
+
+ AddNode (parent,
+ 0, // attribute
+ prevSibling,
+ writerDepth,
+ XPathNodeType.Whitespace,
+ null,
+ false,
+ null,
+ String.Empty,
+ String.Empty,
+ data,
+ null,
+ 0, // nsIndex
+ 0, // line info
+ 0);
+ }
+
+ public override void WriteStartDocument ()
+ {
+ // do nothing
+ }
+
+ public override void WriteStartDocument (bool standalone)
+ {
+ // do nothing
+ }
+
+ public override void WriteEndDocument ()
+ {
+ // do nothing
+ }
+
+ public override void WriteStartElement (string prefix, string localName, string ns)
+ {
+ switch (state) {
+ case WriteState.Element:
+ CloseStartElement ();
+ break;
+ case WriteState.Start:
+ case WriteState.Prolog:
+ case WriteState.Content:
+ break;
+ default:
+ throw new InvalidOperationException ("Invalid document state for writing element: " + state);
+ }
+
+ int parent = GetParentIndex ();
+ UpdateTreeForAddition ();
+
+ WriteStartElement (parent, prevSibling, prefix, localName, ns);
+ state = WriteState.Element;
+ }
+
+ private void WriteStartElement (int parent, int previousSibling, string prefix, string localName, string ns)
+ {
+ PrepareStartElement (previousSibling);
+
+ AddNode (parent,
+ 0, // dummy:firstAttribute
+ previousSibling,
+ writerDepth,
+ 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;
+ }
+ }
+
+ public override void WriteEndElement ()
+ {
+ WriteEndElement (false);
+ }
+
+ public override void WriteFullEndElement ()
+ {
+ WriteEndElement (true);
+ }
+
+ private void WriteEndElement (bool full)
+ {
+ switch (state) {
+ case WriteState.Element:
+ CloseStartElement ();
+ break;
+ case WriteState.Content:
+ break;
+ default:
+ throw new InvalidOperationException ("Invalid state for writing EndElement: " + state);
+ }
+ parentForFirstChild = -1;
+ if (nodes [nodeIndex].NodeType == XPathNodeType.Element) {
+ if (!full)
+ nodes [nodeIndex].IsEmptyElement = true;
+ }
+
+ writerDepth--;
+ }
+
+ public override void WriteStartAttribute (string prefix, string localName, string ns)
+ {
+ if (state != WriteState.Element)
+ throw new InvalidOperationException ("Invalid document state for attribute: " + state);
+
+ state = WriteState.Attribute;
+ 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
+ }
+
+ 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 ()
+ {
+ if (state != WriteState.Attribute)
+ throw new InvalidOperationException ();
+
+ openNamespace = false;
+ state = WriteState.Element;
+ }
+
+ public override void WriteString (string text)
+ {
+ if (WriteState == WriteState.Attribute) {
+ if (openNamespace)
+ namespaces [nsIndex].Namespace += text;
+ else
+ attributes [attributeIndex].Value += text;
+ }
+ else
+ AddTextNode (text);
+ }
+
+ // Well, they cannot be supported, but actually used to
+ // disable-output-escaping = "true"
+ public override void WriteRaw (string data)
+ {
+ WriteString (data);
+ }
+
+ public override void WriteRaw (char [] data, int start, int len)
+ {
+ WriteString (new string (data, start, len));
+ }
+
+ public override void WriteName (string name)
+ {
+ WriteString (name);
+ }
+
+ public override void WriteNmToken (string name)
+ {
+ WriteString (name);
+ }
+
+ public override void WriteBase64 (byte [] buffer, int index, int count)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteBinHex (byte [] buffer, int index, int count)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteChars (char [] buffer, int index, int count)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteCharEntity (char c)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteDocType (string name, string pub, string sys, string intSubset)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteEntityRef (string name)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteQualifiedName (string localName, string ns)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteSurrogateCharEntity (char high, char low)
+ {
+ throw new NotSupportedException ();
+ }
+
+ private bool IsWhitespace (string data)
+ {
+ for (int i = 0; i < data.Length; i++) {
+ switch (data [i]) {
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ continue;
+ default:
+ return false;
+ }
+ }
+ return true;
+ }
+ #endregion
+ }
+}
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs
new file mode 100755
index 00000000000..6bd8a339a0e
--- /dev/null
+++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNavigator.cs
@@ -0,0 +1,630 @@
+//
+// Mono.Xml.XPath.DTMXPathNavigator
+//
+// Author:
+// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
+//
+// (C) 2003 Atsushi Enomoto
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections;
+using System.Text;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.XPath;
+
+namespace Mono.Xml.XPath
+{
+#if OUTSIDE_SYSTEM_XML
+ public
+#else
+ internal
+#endif
+ class DTMXPathNavigator : XPathNavigator, IXmlLineInfo
+ {
+
+#region Copy of XPathDocument
+ public DTMXPathNavigator (DTMXPathDocument document,
+ XmlNameTable nameTable,
+ DTMXPathLinkedNode [] nodes,
+ DTMXPathAttributeNode [] attributes,
+ DTMXPathNamespaceNode [] namespaces,
+ Hashtable idTable)
+ {
+ this.nodes = nodes;
+ this.attributes = attributes;
+ this.namespaces = namespaces;
+ this.idTable = idTable;
+ this.nameTable = nameTable;
+
+ this.MoveToRoot ();
+ this.document = document;
+ }
+
+ // Copy constructor including position informations.
+ public DTMXPathNavigator (DTMXPathNavigator org)
+ : this (org.document, org.nameTable,
+ org.nodes, org.attributes, org.namespaces,
+ org.idTable)
+ {
+ currentIsNode = org.currentIsNode;
+ currentIsAttr = org.currentIsAttr;
+
+ currentNode = org.currentNode;
+ currentAttr = org.currentAttr;
+ currentNs = org.currentNs;
+ }
+
+ XmlNameTable nameTable;
+
+ // Created XPathDocument. This is used to identify the origin of the navigator.
+ DTMXPathDocument document;
+
+ DTMXPathLinkedNode [] nodes;// = new DTMXPathLinkedNode [0];
+ DTMXPathAttributeNode [] attributes;// = new DTMXPathAttributeNode [0];
+ DTMXPathNamespaceNode [] namespaces;// = new DTMXPathNamespaceNode [0];
+
+ // ID table
+ Hashtable idTable;
+
+// // Key table (considered xsd:keyref for XPath 2.0)
+// Hashtable keyRefTable; // [string key-name] -> idTable
+// // idTable [string value] -> int nodeId
+#endregion
+
+ bool currentIsNode;
+ bool currentIsAttr;
+
+ int currentNode;
+ int currentAttr;
+ int currentNs;
+
+ StringBuilder valueBuilder;
+
+#region Ctor
+
+ internal DTMXPathNavigator (XmlNameTable nt)
+ {
+ this.nameTable = nt;
+ }
+
+#endregion
+
+#region Properties
+
+ public override string BaseURI {
+ get { return nodes [currentNode].BaseURI; }
+ }
+
+ public override bool HasAttributes {
+ get { return currentIsNode ? nodes [currentNode].FirstAttribute != 0 : false; }
+ }
+
+ public override bool HasChildren {
+ get { return currentIsNode ? nodes [currentNode].FirstChild != 0 : false; }
+ }
+
+ public override bool IsEmptyElement {
+ get { return currentIsNode ? nodes [currentNode].IsEmptyElement : false; }
+ }
+
+ int IXmlLineInfo.LineNumber {
+ get {
+ return currentIsAttr ? attributes [currentAttr].LineNumber :
+ nodes [currentNode].LineNumber;
+ }
+ }
+
+ int IXmlLineInfo.LinePosition {
+ get {
+ return currentIsAttr ? attributes [currentAttr].LinePosition :
+ nodes [currentNode].LinePosition;
+ }
+ }
+
+ public override string LocalName {
+ get {
+ if (currentIsNode)
+ return nodes [currentNode].LocalName;
+ else if (currentIsAttr)
+ return attributes [currentAttr].LocalName;
+ else
+ return namespaces [currentNs].Name;
+ }
+ }
+
+ // It maybe scarcely used, so I decided to compute it always.
+ public override string Name {
+ get {
+ string prefix;
+ string localName;
+ if (currentIsNode) {
+ prefix = nodes [currentNode].Prefix;
+ localName = nodes [currentNode].LocalName;
+ } else if (currentIsAttr) {
+ prefix = attributes [currentAttr].Prefix;
+ localName = attributes [currentAttr].LocalName;
+ } else
+ return namespaces [currentNs].Name;
+
+ if (prefix != "")
+ return prefix + ':' + localName;
+ else
+ return localName;
+ }
+ }
+
+ public override string NamespaceURI {
+ get {
+ if (currentIsNode)
+ return nodes [currentNode].NamespaceURI;
+ if (currentIsAttr)
+ return attributes [currentAttr].NamespaceURI;
+ return String.Empty;
+ }
+ }
+
+ public override XmlNameTable NameTable {
+ get { return nameTable; }
+ }
+
+ public override XPathNodeType NodeType {
+ get {
+ if (currentIsNode)
+ return nodes [currentNode].NodeType;
+ else if (currentIsAttr)
+ return XPathNodeType.Attribute;
+ else
+ return XPathNodeType.Namespace;
+ }
+ }
+
+ public override string Prefix {
+ get {
+ if (currentIsNode)
+ return nodes [currentNode].Prefix;
+ else if (currentIsAttr)
+ return attributes [currentAttr].Prefix;
+ return String.Empty;
+ }
+ }
+
+ public override string Value {
+ get {
+ if (currentIsAttr)
+ return attributes [currentAttr].Value;
+ else if (!currentIsNode)
+ return namespaces [currentNs].Namespace;
+
+ switch (nodes [currentNode].NodeType) {
+ case XPathNodeType.Comment:
+ case XPathNodeType.ProcessingInstruction:
+ case XPathNodeType.Text:
+ case XPathNodeType.Whitespace:
+ case XPathNodeType.SignificantWhitespace:
+ return nodes [currentNode].Value;
+ }
+
+ // Element
+ if (valueBuilder == null)
+ valueBuilder = new StringBuilder ();
+ else
+ valueBuilder.Length = 0;
+
+ int iter = nodes [currentNode].FirstChild;
+ int depth = nodes [currentNode].Depth;
+ while (iter < nodes.Length && nodes [iter].Depth > depth) {
+ switch (nodes [iter].NodeType) {
+ case XPathNodeType.Comment:
+ case XPathNodeType.ProcessingInstruction:
+ break;
+ default:
+ valueBuilder.Append (nodes [iter].Value);
+ break;
+ }
+ iter++;
+ }
+
+ return valueBuilder.ToString ();
+ }
+ }
+
+ public override string XmlLang {
+ get { return nodes [currentNode].XmlLang; }
+ }
+
+#endregion
+
+#region Methods
+
+ public override XPathNavigator Clone ()
+ {
+ return new DTMXPathNavigator (this);
+ }
+
+ public override XmlNodeOrder ComparePosition (XPathNavigator nav)
+ {
+ DTMXPathNavigator another = nav as DTMXPathNavigator;
+
+ if (another == null || another.document != this.document)
+ return XmlNodeOrder.Unknown;
+
+ if (currentNode > another.currentNode)
+ return XmlNodeOrder.After;
+ else if (currentNode < another.currentNode)
+ return XmlNodeOrder.Before;
+
+ // another may attr or ns,
+ // and this may be also attr or ns.
+ if (another.currentIsAttr) {
+ if (this.currentIsAttr) {
+ if (currentAttr > another.currentAttr)
+ return XmlNodeOrder.After;
+ else if (currentAttr < another.currentAttr)
+ return XmlNodeOrder.Before;
+ else
+ return XmlNodeOrder.Same;
+ } else
+ return XmlNodeOrder.Before;
+ } else if (!another.currentIsNode) {
+ if (!this.currentIsNode) {
+ if (currentNs > another.currentNs)
+ return XmlNodeOrder.After;
+ else if (currentNs < another.currentNs)
+ return XmlNodeOrder.Before;
+ else
+ return XmlNodeOrder.Same;
+ } else
+ return XmlNodeOrder.Before;
+ } else
+ return !another.currentIsNode ? XmlNodeOrder.Before : XmlNodeOrder.Same;
+ }
+
+ private int findAttribute (string localName, string namespaceURI)
+ {
+ if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
+ int cur = nodes [currentNode].FirstAttribute;
+ while (cur != 0) {
+ if (attributes [cur].LocalName == localName && attributes [cur].NamespaceURI == namespaceURI)
+ return cur;
+ cur = attributes [cur].NextAttribute;
+ }
+ }
+ return 0;
+ }
+
+ public override string GetAttribute (string localName,
+ string namespaceURI)
+ {
+ int attr = findAttribute (localName, namespaceURI);
+ return (attr != 0) ? attributes [attr].Value : String.Empty;
+ }
+
+ public override string GetNamespace (string name)
+ {
+ if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
+ int nsNode = nodes [currentNode].FirstNamespace;
+ while (nsNode != 0) {
+ if (namespaces [nsNode].Name == name)
+ return namespaces [nsNode].Namespace;
+ nsNode = namespaces [nsNode].NextNamespace;
+ }
+ }
+ return String.Empty;
+ }
+
+ bool IXmlLineInfo.HasLineInfo ()
+ {
+ return true;
+ }
+
+ public override bool IsDescendant (XPathNavigator nav)
+ {
+ DTMXPathNavigator another = nav as DTMXPathNavigator;
+
+ if (another == null || another.document != this.document)
+ return false;
+
+ // Maybe we can improve here more efficiently by
+ // comparing node indices.
+ if (another.currentNode == currentNode)
+ return !another.currentIsNode;
+ int tmp = nodes [another.currentNode].Parent;
+ while (tmp != 0) {
+ if (tmp == currentNode)
+ return true;
+ tmp = nodes [tmp].Parent;
+ }
+ return false;
+ }
+
+ public override bool IsSamePosition (XPathNavigator other)
+ {
+ DTMXPathNavigator another = other as DTMXPathNavigator;
+
+ if (another == null || another.document != this.document)
+ return false;
+
+ if (this.currentNode != another.currentNode ||
+ this.currentIsAttr != another.currentIsAttr ||
+ this.currentIsNode != another.currentIsNode)
+ return false;
+
+ if (currentIsAttr)
+ return this.currentAttr == another.currentAttr;
+ else if (!currentIsNode)
+ return this.currentNs == another.currentNs;
+ return true;
+ }
+
+ public override bool MoveTo (XPathNavigator other)
+ {
+ DTMXPathNavigator another = other as DTMXPathNavigator;
+
+ if (another == null || another.document != this.document)
+ return false;
+
+ this.currentNode = another.currentNode;
+ this.currentAttr = another.currentAttr;
+ this.currentNs = another.currentNs;
+ this.currentIsNode = another.currentIsNode;
+ this.currentIsAttr = another.currentIsAttr;
+ return true;
+ }
+
+ public override bool MoveToAttribute (string localName,
+ string namespaceURI)
+ {
+ int attr = findAttribute (localName, namespaceURI);
+ if (attr == 0)
+ return false;
+
+ currentAttr = attr;
+ currentIsAttr = true;
+ currentIsNode = false;
+ return true;
+ }
+
+ public override bool MoveToFirst ()
+ {
+ if (currentIsAttr)
+ return false;
+
+ int cur = nodes [currentNode].PreviousSibling;
+ if (cur == 0)
+ return false;
+
+ int next = cur;
+ while (next != 0) {
+ cur = next;
+ next = nodes [cur].PreviousSibling;
+ }
+ currentNode = cur;
+ currentIsNode = true;
+ return true;
+ }
+
+ public override bool MoveToFirstAttribute ()
+ {
+ if (!currentIsNode)
+ return false;
+
+ int first = nodes [currentNode].FirstAttribute;
+ if (first == 0)
+ return false;
+
+ currentAttr = first;
+ currentIsAttr = true;
+ currentIsNode = false;
+ return true;
+ }
+
+ public override bool MoveToFirstChild ()
+ {
+ if (!currentIsNode)
+ return false;
+
+ int first = nodes [currentNode].FirstChild;
+ if (first == 0)
+ return false;
+
+ currentNode = first;
+ return true;
+ }
+
+ private bool moveToSpecifiedNamespace (int cur,
+ XPathNamespaceScope namespaceScope)
+ {
+ if (cur == 0)
+ return false;
+
+ if (namespaceScope == XPathNamespaceScope.Local &&
+ namespaces [cur].DeclaredElement != currentNode)
+ return false;
+
+ if (namespaceScope != XPathNamespaceScope.All
+ && namespaces [cur].Namespace == XmlNamespaces.XML)
+ return false;
+
+ if (cur != 0) {
+ moveToNamespace (cur);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ public override bool MoveToFirstNamespace (
+ XPathNamespaceScope namespaceScope)
+ {
+ if (!currentIsNode)
+ return false;
+ int cur = nodes [currentNode].FirstNamespace;
+ return moveToSpecifiedNamespace (cur, namespaceScope);
+ }
+
+ // Note that this support is extension to XPathDocument.
+ // XPathDocument does not support ID reference.
+ public override bool MoveToId (string id)
+ {
+ if (idTable.ContainsKey (id)) {
+ currentNode = (int) idTable [id];
+ currentIsNode = true;
+ currentIsAttr = false;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ private void moveToNamespace (int nsNode)
+ {
+ currentIsNode = currentIsAttr = false;
+ currentNs = nsNode;
+ }
+
+ public override bool MoveToNamespace (string name)
+ {
+ int cur = nodes [currentNode].FirstNamespace;
+ if (cur == 0)
+ return false;
+
+ while (cur != 0) {
+ if (namespaces [cur].Name == name) {
+ moveToNamespace (cur);
+ return true;
+ }
+ cur = namespaces [cur].NextNamespace;
+ }
+ return false;
+ }
+
+ public override bool MoveToNext ()
+ {
+ if (currentIsAttr)
+ return false;
+
+ int next = nodes [currentNode].NextSibling;
+ if (next == 0)
+ return false;
+ currentNode = next;
+ currentIsNode = true;
+ return true;
+ }
+
+ public override bool MoveToNextAttribute ()
+ {
+ if (!currentIsAttr)
+ return false;
+
+ int next = attributes [currentAttr].NextAttribute;
+ if (next == 0)
+ return false;
+ currentAttr = next;
+ return true;
+ }
+
+ public override bool MoveToNextNamespace (
+ XPathNamespaceScope namespaceScope)
+ {
+ if (currentIsAttr || currentIsNode)
+ return false;
+
+ int cur = namespaces [currentNs].NextNamespace;
+ return moveToSpecifiedNamespace (cur, namespaceScope);
+ }
+
+ public override bool MoveToParent ()
+ {
+ if (!currentIsNode) {
+ currentIsNode = true;
+ currentIsAttr = false;
+ return true;
+ }
+
+ int parent = nodes [currentNode].Parent;
+ if (parent == 0) // It is root itself.
+ return false;
+
+ currentNode = parent;
+ return true;
+ }
+
+ public override bool MoveToPrevious ()
+ {
+ if (currentIsAttr)
+ return false;
+
+ int previous = nodes [currentNode].PreviousSibling;
+ if (previous == 0)
+ return false;
+ currentNode = previous;
+ currentIsNode = true;
+ return true;
+ }
+
+ public override void MoveToRoot ()
+ {
+ currentNode = 1; // root is 1.
+ currentIsNode = true;
+ currentIsAttr = false;
+ }
+
+#endregion
+
+ /*
+ public string DebugDump {
+ get {
+ StringBuilder sb = new StringBuilder ();
+
+ for (int i = 0; i < namespaces.Length; i++) {
+ DTMXPathNamespaceNode n = namespaces [i];
+ sb.AppendFormat ("{0}: {1},{2} {3}/{4}\n", i,
+ n.DeclaredElement, n.NextNamespace,
+ n.Name, n.Namespace);
+ }
+
+ for (int i=0; i<this.nodes.Length; i++) {
+ DTMXPathLinkedNode n = nodes [i];
+ sb.AppendFormat ("{0}: {1}:{2} {3} {4} {5} {6} {7}\n", new object [] {i, n.Prefix, n.LocalName, n.NamespaceURI, n.FirstNamespace, n.FirstAttribute, n.FirstChild, n.Parent});
+ }
+
+ for (int i=0; i<this.attributes.Length; i++) {
+ DTMXPathAttributeNode n = attributes [i];
+ sb.AppendFormat ("{0}: {1}:{2} {3} {4}\n", i, n.Prefix, n.LocalName, n.NamespaceURI, n.NextAttribute);
+ }
+
+ return sb.ToString ();
+ }
+ }
+ */
+
+ }
+
+ internal class XmlNamespaces
+ {
+ public const string XML = "http://www.w3.org/XML/1998/namespace";
+ public const string XMLNS = "http://www.w3.org/2000/xmlns/";
+ }
+}
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNode.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNode.cs
new file mode 100755
index 00000000000..11d22e29477
--- /dev/null
+++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/DTMXPathNode.cs
@@ -0,0 +1,107 @@
+//
+// Mono.Xml.XPath.DTMXPathNode.cs
+//
+// Author:
+// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
+//
+// (C) 2003 Atsushi Enomoto
+//
+// These classes represent each node of DTMXPathNavigator.
+//
+//#define DTM_CLASS
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml.XPath;
+
+namespace Mono.Xml.XPath
+{
+#if OUTSIDE_SYSTEM_XML
+ public
+#else
+ internal
+#endif
+#if DTM_CLASS
+ class DTMXPathLinkedNode
+#else
+ struct DTMXPathLinkedNode
+#endif
+ {
+ public int FirstChild;
+ public int Parent;
+ public int PreviousSibling;
+ public int NextSibling;
+ public int FirstAttribute;
+ public int FirstNamespace;
+ public int Depth;
+ public XPathNodeType NodeType;
+ public string BaseURI;
+ public bool IsEmptyElement;
+ public string LocalName;
+ public string NamespaceURI;
+ public string Prefix;
+ public string Value;
+ public string XmlLang;
+ public int LineNumber;
+ public int LinePosition;
+ }
+
+#if OUTSIDE_SYSTEM_XML
+ public
+#else
+ internal
+#endif
+#if DTM_CLASS
+ class DTMXPathAttributeNode
+#else
+ struct DTMXPathAttributeNode
+#endif
+ {
+ public int OwnerElement;
+ public int NextAttribute;
+ public string LocalName;
+ public string NamespaceURI;
+ public string Prefix;
+ public string Value;
+ public object SchemaType;
+ public int LineNumber;
+ public int LinePosition;
+ }
+
+#if OUTSIDE_SYSTEM_XML
+ public
+#else
+ internal
+#endif
+#if DTM_CLASS
+ class DTMXPathNamespaceNode
+#else
+ struct DTMXPathNamespaceNode
+#endif
+ {
+ public int DeclaredElement;
+ public int NextNamespace;
+ public string Name;
+ public string Namespace;
+ }
+}
diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/XPathEditableDocument.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/XPathEditableDocument.cs
new file mode 100755
index 00000000000..828a0414f05
--- /dev/null
+++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath/XPathEditableDocument.cs
@@ -0,0 +1,765 @@
+//
+// Mono.Xml.XPath.XPathEditableDocument
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// (C)2004 Novell Inc.
+//
+// Yet another implementation of editable XPathNavigator.
+// (Even runnable under MS.NET 2.0)
+//
+// By rewriting XPathEditableDocument.CreateNavigator() as just to
+// create XmlDocumentNavigator, XmlDocumentEditableNavigator could be used
+// as to implement XmlDocument.CreateNavigator().
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.IO;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.XPath;
+using System.Xml.Serialization;
+
+namespace Mono.Xml.XPath
+{
+ public class XPathEditableDocument : IXPathNavigable
+ {
+ /*
+ public static void Main ()
+ {
+ try {
+#if true
+ XmlDocument doc = new XmlDocument ();
+ XPathEditableDocument pd = new XPathEditableDocument (doc);
+ XPathNavigator nav = pd.CreateNavigator ();
+ IChangeTracking xp = pd;
+#else
+ XPathDocument doc = new XPathDocument ();
+ XPathNavigator nav = doc.CreateNavigator ();
+ IChangeTracking xp = doc;
+#endif
+ doc.LoadXml ("<root/>");
+ nav.MoveToFirstChild (); // root
+ XmlWriter w = nav.AppendChild ();
+ Console.WriteLine (((IChangeTracking) xp).IsChanged);
+ w.WriteElementString ("foo", "foo_text");
+ w.WriteElementString ("bar", "bar_text");
+ w.WriteStartElement ("hoge");
+ w.WriteAttributeString ("fuga", "fugafuga");
+ w.WriteAttributeString ("unya", "unyaunya");
+ w.WriteFullEndElement ();
+ w.Close ();
+
+ w = nav.CreateAttributes ();
+ w.WriteStartAttribute ("namara");
+ w.WriteString ("mokera");
+ w.WriteEndAttribute ();
+ w.WriteAttributeString ("beccho", "giccho");
+ w.Close ();
+
+ nav.MoveToRoot ();
+ nav.MoveToFirstChild ();
+ nav.MoveToFirstChild ();
+ nav.DeleteSelf (); // delete foo
+ Console.WriteLine (nav.Name);
+ nav.MoveToNext ();
+ Console.WriteLine (nav.Name);
+ Console.WriteLine (nav.MoveToFirstAttribute ());
+ nav.DeleteSelf (); // delete fuga
+
+ doc.Save (Console.Out);
+ } catch (Exception ex) {
+ Console.WriteLine (ex);
+ }
+ }
+ */
+
+ XmlDocument document;
+
+ ArrayList changes = new ArrayList ();
+
+ public XPathEditableDocument (XmlDocument doc)
+ {
+ document = doc;
+ }
+
+ public XPathNavigator CreateNavigator ()
+ {
+ return document.CreateNavigator ();
+ }
+
+ public XmlWriter CreateWriter ()
+ {
+ return CreateNavigator ().AppendChild ();
+ }
+
+ public bool HasChanges ()
+ {
+ return IsChanged;
+ }
+
+ #region IRevertibleChangeTracking/IChangeTracking
+ public bool IsChanged {
+ get { return changes.Count != 0; }
+ }
+
+ public void AcceptChanges ()
+ {
+ changes.Clear ();
+ }
+
+ public void RejectChanges ()
+ {
+ for (int i = changes.Count - 1; i >= 0; i--) {
+ Insertion ins = changes [i] as Insertion;
+ if (ins != null) {
+ ins.ParentNode.RemoveChild (ins.InsertedNode);
+ continue;
+ }
+
+ Removal rem = changes [i] as Removal;
+ if (rem != null) {
+ if (rem.RemovedNode.NodeType == XmlNodeType.Attribute) {
+ XmlElement el = (XmlElement) rem.OwnerNode;
+ el.SetAttributeNode ((XmlAttribute) rem.RemovedNode);
+ }
+ else
+ rem.OwnerNode.InsertBefore (rem.RemovedNode, rem.NextSibling);
+ continue;
+ }
+ AttributeUpdate au = changes [i] as AttributeUpdate;
+ if (au != null) {
+ if (au.OldAttribute != null)
+ au.Element.SetAttributeNode (au.OldAttribute);
+ else
+ au.Element.RemoveAttributeNode (au.NewAttribute);
+ continue;
+ }
+ }
+ changes.Clear ();
+ }
+ #endregion
+
+ #region IXmlSerializable
+ public void WriteXml (XmlWriter writer)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void ReadXml (XmlReader reader)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public XmlSchema GetSchema ()
+ {
+ throw new NotImplementedException ();
+ }
+ #endregion
+
+ internal bool DeleteNode (XmlNode node)
+ {
+ Removal rem = new Removal ();
+ if (node.NodeType == XmlNodeType.Attribute) {
+ XmlAttribute attr = node as XmlAttribute;
+ rem.OwnerNode = attr.OwnerElement;
+ rem.RemovedNode = node;
+ attr.OwnerElement.RemoveAttributeNode (attr);
+ return false;
+ } else {
+ rem.OwnerNode = node.ParentNode;
+ rem.NextSibling = node.NextSibling;
+ rem.RemovedNode = node;
+ node.ParentNode.RemoveChild (node);
+ return rem.NextSibling != null;
+ }
+ }
+
+ internal XmlWriter CreateInsertionWriter (XmlNode owner, XmlNode previousSibling)
+ {
+ return new XmlDocumentInsertionWriter (owner, previousSibling, this);
+ }
+
+ internal XmlWriter CreateAttributesWriter (XmlNode owner)
+ {
+ return new XmlDocumentAttributeWriter (owner, this);
+ }
+
+ internal void AttributeUpdate (XmlElement element, XmlAttribute oldAttr, XmlAttribute newAttr)
+ {
+ AttributeUpdate au = new AttributeUpdate ();
+ au.Element = element;
+ au.OldAttribute = oldAttr;
+ au.NewAttribute = newAttr;
+ changes.Add (au);
+ }
+
+ internal void AppendChild (XmlNode parent, XmlNode child)
+ {
+ Insertion ins = new Insertion ();
+ ins.ParentNode = parent;
+ ins.InsertedNode = child;
+ changes.Add (ins);
+ }
+ }
+
+ public class XmlDocumentInsertionWriter : XmlWriter
+ {
+ XmlNode current;
+ XmlNode previousSibling;
+ XPathEditableDocument document;
+ Stack nodeStack = new Stack ();
+
+ public XmlDocumentInsertionWriter (XmlNode owner, XmlNode previousSibling, XPathEditableDocument doc)
+ {
+ this.current = (XmlNode) owner;
+ if (current == null)
+ throw new InvalidOperationException ();
+ this.previousSibling = previousSibling;
+ this.document = doc;
+ state = WriteState.Content;
+ }
+
+ WriteState state;
+ XmlAttribute attribute;
+
+ public override WriteState WriteState {
+ get { return state; }
+ }
+
+ public override void Close ()
+ {
+ }
+
+ public override void Flush ()
+ {
+ }
+
+ public override string LookupPrefix (string ns)
+ {
+ return current.GetPrefixOfNamespace (ns);
+ }
+
+ public override void WriteStartAttribute (string prefix, string name, string ns)
+ {
+ if (state != WriteState.Content)
+ throw new InvalidOperationException ("Current state is not inside element. Cannot start attribute.");
+ attribute = current.OwnerDocument.CreateAttribute (prefix, name, ns);
+ state = WriteState.Attribute;
+ }
+
+ public override void WriteProcessingInstruction (string name, string value)
+ {
+ XmlProcessingInstruction pi = current.OwnerDocument.CreateProcessingInstruction (name, value);
+ current.AppendChild (pi);
+ document.AppendChild (current, pi);
+ }
+
+ public override void WriteComment (string text)
+ {
+ XmlComment comment = current.OwnerDocument.CreateComment (text);
+ current.AppendChild (comment);
+ document.AppendChild (current, comment);
+ }
+
+ public override void WriteCData (string text)
+ {
+ XmlCDataSection cdata = current.OwnerDocument.CreateCDataSection (text);
+ current.AppendChild (cdata);
+ document.AppendChild (current, cdata);
+ }
+
+ public override void WriteStartElement (string prefix, string name, string ns)
+ {
+ if (current.OwnerDocument == null)
+ throw new Exception ("Should not happen.");
+ XmlElement el = current.OwnerDocument.CreateElement (prefix, name, ns);
+ current.AppendChild (el);
+ document.AppendChild (current, el);
+ nodeStack.Push (current);
+ current = el;
+ }
+
+ public override void WriteEndElement ()
+ {
+ if (nodeStack.Count == 0)
+ throw new InvalidOperationException ("No element is opened.");
+ current = nodeStack.Pop () as XmlNode;
+ }
+
+ public override void WriteFullEndElement ()
+ {
+ WriteEndElement ();
+ XmlElement el = current as XmlElement;
+ if (el != null)
+ el.IsEmpty = false;
+ }
+
+ public override void WriteDocType (string name, string pubid, string systemId, string intsubset)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteStartDocument ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteStartDocument (bool standalone)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteEndDocument ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteBase64 (byte [] data, int start, int length)
+ {
+ WriteString (Convert.ToBase64String (data, start, length));
+ }
+
+ public override void WriteRaw (char [] raw, int start, int length)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteRaw (string raw)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteSurrogateCharEntity (char msb, char lsb)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteCharEntity (char c)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteEntityRef (string entname)
+ {
+ if (state != WriteState.Attribute)
+ throw new InvalidOperationException ("Current state is not inside attribute. Cannot write attribute value.");
+ attribute.AppendChild (attribute.OwnerDocument.CreateEntityReference (entname));
+ }
+
+ public override void WriteChars (char [] data, int start, int length)
+ {
+ WriteString (new string (data, start, length));
+ }
+
+ public override void WriteString (string text)
+ {
+ if (attribute != null)
+ attribute.Value += text;
+ else {
+ XmlText t = current.OwnerDocument.CreateTextNode (text);
+ current.AppendChild (t);
+ document.AppendChild (current, t);
+ }
+ }
+
+ public override void WriteWhitespace (string text)
+ {
+ if (state != WriteState.Attribute)
+ current.AppendChild (current.OwnerDocument.CreateTextNode (text));
+ else if (attribute.ChildNodes.Count == 0)
+ attribute.AppendChild (attribute.OwnerDocument.CreateWhitespace (text));
+ else
+ attribute.Value += text;
+ }
+
+ public override void WriteEndAttribute ()
+ {
+ XmlElement element = current as XmlElement;
+ if (state != WriteState.Attribute || element == null)
+ throw new InvalidOperationException ("Current state is not inside attribute. Cannot close attribute.");
+ document.AttributeUpdate (element, element.SetAttributeNode (attribute), attribute);
+ attribute = null;
+ state = WriteState.Content;
+ }
+ }
+
+ public class XmlDocumentAttributeWriter : XmlWriter
+ {
+ XmlElement element;
+ XPathEditableDocument document;
+
+ public XmlDocumentAttributeWriter (XmlNode owner, XPathEditableDocument doc)
+ {
+ element = owner as XmlElement;
+ if (element == null)
+ throw new ArgumentException ("To write attributes, current node must be an element.");
+ state = WriteState.Content;
+ document = doc;
+ }
+
+ WriteState state;
+ XmlAttribute attribute;
+
+ public override WriteState WriteState {
+ get { return state; }
+ }
+
+ public override void Close ()
+ {
+ }
+
+ public override void Flush ()
+ {
+ }
+
+ public override string LookupPrefix (string ns)
+ {
+ return element.GetPrefixOfNamespace (ns);
+ }
+
+ public override void WriteStartAttribute (string prefix, string name, string ns)
+ {
+ if (state != WriteState.Content)
+ throw new InvalidOperationException ("Current state is not inside element. Cannot start attribute.");
+ attribute = element.OwnerDocument.CreateAttribute (prefix, name, ns);
+ state = WriteState.Attribute;
+ }
+
+ public override void WriteProcessingInstruction (string name, string value)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteComment (string text)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteCData (string text)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteStartElement (string prefix, string name, string ns)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteEndElement ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteFullEndElement ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteDocType (string name, string pubid, string systemId, string intsubset)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteStartDocument ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteStartDocument (bool standalone)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteEndDocument ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteBase64 (byte [] data, int start, int length)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteRaw (char [] raw, int start, int length)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteRaw (string raw)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteSurrogateCharEntity (char msb, char lsb)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteCharEntity (char c)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override void WriteEntityRef (string entname)
+ {
+ if (state != WriteState.Attribute)
+ throw new InvalidOperationException ("Current state is not inside attribute. Cannot write attribute value.");
+ attribute.AppendChild (attribute.OwnerDocument.CreateEntityReference (entname));
+ }
+
+ public override void WriteChars (char [] data, int start, int length)
+ {
+ WriteString (new string (data, start, length));
+ }
+
+ public override void WriteString (string text)
+ {
+ if (state != WriteState.Attribute)
+ throw new InvalidOperationException ("Current state is not inside attribute. Cannot write attribute value.");
+ attribute.Value += text;
+ }
+
+ public override void WriteWhitespace (string text)
+ {
+ if (state != WriteState.Attribute)
+ throw new InvalidOperationException ("Current state is not inside attribute. Cannot write attribute value.");
+ if (attribute.ChildNodes.Count == 0)
+ attribute.AppendChild (attribute.OwnerDocument.CreateWhitespace (text));
+ else
+ attribute.Value += text;
+ }
+
+ public override void WriteEndAttribute ()
+ {
+ if (state != WriteState.Attribute)
+ throw new InvalidOperationException ("Current state is not inside attribute. Cannot close attribute.");
+ document.AttributeUpdate (element, element.SetAttributeNode (attribute), attribute);
+ attribute = null;
+ state = WriteState.Content;
+ }
+ }
+
+ public class Insertion
+ {
+ // AppendChild : last child / true
+ // InsertBefore : current node / false
+ // InsertAfter : current node / true
+ // PrependChild : first child / false
+ public XmlNode ParentNode;
+ public XmlNode InsertedNode;
+ public bool Afterward;
+ }
+
+ public class Removal
+ {
+ public XmlNode OwnerNode;
+ public XmlNode NextSibling;
+ public XmlNode RemovedNode;
+ }
+
+ public class AttributeUpdate
+ {
+ public XmlElement Element;
+ public XmlAttribute NewAttribute;
+ public XmlAttribute OldAttribute;
+ }
+
+ public class XmlDocumentEditableNavigator : XPathNavigator, IHasXmlNode
+ {
+ XPathEditableDocument document;
+ XPathNavigator navigator;
+
+ public XmlDocumentEditableNavigator (XPathEditableDocument doc)
+ {
+ document = doc;
+ navigator = doc.CreateNavigator ();
+ }
+
+ public XmlDocumentEditableNavigator (XmlDocumentEditableNavigator nav)
+ {
+ document = nav.document;
+ navigator = nav.navigator.Clone ();
+ }
+
+ public override string BaseURI {
+ get { return navigator.BaseURI; }
+ }
+
+ public override bool IsEmptyElement {
+ get { return navigator.IsEmptyElement; }
+ }
+
+ public override string LocalName {
+ get { return navigator.LocalName; }
+ }
+
+ public override XmlNameTable NameTable {
+ get { return navigator.NameTable; }
+ }
+
+ public override string Name {
+ get { return navigator.Name; }
+ }
+
+ public override string NamespaceURI {
+ get { return navigator.NamespaceURI; }
+ }
+
+ public override XPathNodeType NodeType {
+ get { return navigator.NodeType; }
+ }
+
+ public override string Prefix {
+ get { return navigator.Prefix; }
+ }
+
+ public override string Value {
+ get { return navigator.Value; }
+ }
+
+ public override XPathNavigator Clone ()
+ {
+ return new XmlDocumentEditableNavigator (this);
+ }
+
+ public override XPathNavigator CreateNavigator ()
+ {
+ return navigator.Clone ();
+ }
+
+ public XmlNode GetNode ()
+ {
+ return ((IHasXmlNode) navigator).GetNode ();
+ }
+
+ public override bool IsSamePosition (XPathNavigator other)
+ {
+ XmlDocumentEditableNavigator nav = other as XmlDocumentEditableNavigator;
+ if (nav != null)
+ return navigator.IsSamePosition (nav.navigator);
+ else
+ return navigator.IsSamePosition (nav);
+ }
+
+ public override bool MoveTo (XPathNavigator other)
+ {
+ XmlDocumentEditableNavigator nav = other as XmlDocumentEditableNavigator;
+ if (nav != null)
+ return navigator.MoveTo (nav.navigator);
+ else
+ return navigator.MoveTo (nav);
+ }
+
+ public override bool MoveToFirstAttribute ()
+ {
+ return navigator.MoveToFirstAttribute ();
+ }
+
+ public override bool MoveToFirstChild ()
+ {
+ return navigator.MoveToFirstChild ();
+ }
+
+ public override bool MoveToFirstNamespace (XPathNamespaceScope scope)
+ {
+ return navigator.MoveToFirstNamespace (scope);
+ }
+
+ public override bool MoveToId (string id)
+ {
+ return navigator.MoveToId (id);
+ }
+
+ public override bool MoveToNext ()
+ {
+ return navigator.MoveToNext ();
+ }
+
+ public override bool MoveToNextAttribute ()
+ {
+ return navigator.MoveToNextAttribute ();
+ }
+
+ public override bool MoveToNextNamespace (XPathNamespaceScope scope)
+ {
+ return navigator.MoveToNextNamespace (scope);
+ }
+
+ public override bool MoveToParent ()
+ {
+ return navigator.MoveToParent ();
+ }
+
+ public override bool MoveToPrevious ()
+ {
+ return navigator.MoveToPrevious ();
+ }
+
+ public override XmlWriter AppendChild ()
+ {
+ XmlNode n = ((IHasXmlNode) navigator).GetNode ();
+ if (n == null)
+ throw new InvalidOperationException ("Should not happen.");
+ return document.CreateInsertionWriter (n, null);
+ }
+
+ public override XmlWriter InsertBefore ()
+ {
+ XmlNode n = ((IHasXmlNode) navigator).GetNode ();
+ return document.CreateInsertionWriter (n.ParentNode, n.PreviousSibling);
+ }
+
+ public override XmlWriter CreateAttributes ()
+ {
+ XmlNode n = ((IHasXmlNode) navigator).GetNode ();
+ return document.CreateInsertionWriter (n, null);
+ }
+
+ public override bool DeleteSelf ()
+ {
+ XmlNode n = ((IHasXmlNode) navigator).GetNode ();
+ if (!navigator.MoveToNext ())
+ navigator.MoveToParent ();
+ return document.DeleteNode (n);
+ }
+
+ public override void SetValue (string value)
+ {
+ XmlNode n = ((IHasXmlNode) navigator).GetNode ();
+ foreach (XmlNode c in n.ChildNodes)
+ document.DeleteNode (c);
+ XmlWriter w = document.CreateInsertionWriter (n, null);
+ // FIXME: Hmm, it does not look like using it.
+ w.WriteValue (value);
+ w.Close ();
+ }
+ }
+}
+
+#endif