//
// (C) 2003 Atsushi Enomoto
//
+//#define DTM_CLASS
using System;
using System.Collections;
using System.IO;
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)
{
}
}
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)
{
}
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 ();
}
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;
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;
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 ();
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;
case XmlNodeType.Comment:
case XmlNodeType.Text:
case XmlNodeType.ProcessingInstruction:
- if (requireFirstChildFill)
+ if (parentForFirstChild >= 0)
prevSibling = 0;
else
while (nodes [prevSibling].Depth != xmlReader.Depth)
if (prevSibling != 0)
nodes [prevSibling].NextSibling = nodeIndex;
- if (requireFirstChildFill)
+ if (parentForFirstChild >= 0)
nodes [parent].FirstChild = nodeIndex;
break;
case XmlNodeType.Whitespace:
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 ?
skipRead = true;
AddNode (parent,
0,
- attributeIndex,
prevSibling,
xmlReader.Depth,
position,
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,
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)
}
// 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;
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;
}
// 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;
}
}
}
--- /dev/null
+//
+// 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
+ }
+}