2 // Mono.Xml.XPath.DTMXPathDocumentBuilder
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C) 2003 Atsushi Enomoto
10 using System.Collections;
13 using System.Xml.Schema;
14 using System.Xml.XPath;
16 namespace Mono.Xml.XPath
19 public class DTMXPathDocumentBuilder
21 public DTMXPathDocumentBuilder (string url)
22 : this (url, XmlSpace.None)
26 public DTMXPathDocumentBuilder (string url, XmlSpace space)
27 : this (new XmlTextReader (url), space)
31 public DTMXPathDocumentBuilder (XmlReader reader)
32 : this (reader, XmlSpace.None)
36 public DTMXPathDocumentBuilder (XmlReader reader, XmlSpace space)
38 this.xmlReader = reader;
39 this.xmlSpace = xmlSpace;
40 this.nameTable = reader.NameTable;
46 XmlNameTable nameTable;
47 int defaultCapacity = 100;
48 public int DefaultCapacity {
49 get { return defaultCapacity; }
52 throw new ArgumentOutOfRangeException ();
53 defaultCapacity = value;
57 #region Tree node info collections.
59 int [] firstChild_ = new int [0];
60 int [] parent_ = new int [0];
61 int [] firstAttribute_ = new int [0];
62 int [] previousSibling_ = new int [0];
63 int [] nextSibling_ = new int [0];
64 int [] depth_ = new int [0];
65 int [] position_ = new int [0];
66 XPathNodeType [] nodeType_ = new XPathNodeType [0];
67 string [] baseUri_ = new string [0];
68 bool [] isEmptyElement_ = new bool [0];
69 string [] localName_ = new string [0];
70 string [] namespaceUri_ = new string [0];
71 string [] prefix_ = new string [0];
72 string [] value_ = new string [0];
73 string [] xmlLang_ = new string [0];
74 int [] namespaceNode_ = new int [0];
75 object [] schemaType_ = new object [0];
78 int [] ownerElement_ = new int [0];
79 int [] nextAttribute_ = new int [0];
80 string [] attrLocalName_ = new string [0];
81 string [] attrPrefix_ = new string [0];
82 string [] attrNsUri_ = new string [0];
83 string [] attrValue_ = new string [0];
84 object [] attrSchemaType_ = new object [0];
87 int [] nsDeclaredElement_ = new int [100];
88 int [] nextNsNode_ = new int [100];
89 string [] nsNodeName_ = new string [100];
90 string [] nsNodeUri_ = new string [100];
96 bool requireFirstChildFill;
98 public DTMXPathDocument CreateDocument ()
100 return new DTMXPathDocument (nameTable,
136 public void Compile ()
138 // index 0 is dummy. No node (including Root) is assigned to this index
139 // So that we can easily compare index != 0 instead of index < 0.
140 // (Difference between jnz or jbe in 80x86.)
141 AddNode (0, 0, 0, 0, 0, 0, XPathNodeType.All, "", false, "", "", "", "", "", 0, null);
143 AddAttribute (0, null, null, null, null, null);
144 nextAttribute_ [0] = 0;
145 AddNsNode (0, null, null);
148 AddNsNode (1, "xml", XmlNamespaces.XML);
152 AddNode (0, 0, 0, 0, -1, 0, XPathNodeType.Root, xmlReader.BaseURI, false, "", "", "", "", "", 1, null);
155 this.requireFirstChildFill = true;
157 while (!xmlReader.EOF)
159 SetNodeArraysLength (nodeIndex + 1);
160 SetAttributeArraysLength (attributeIndex + 1);
161 SetNsArraysLength (nsIndex + 1);
163 xmlReader = null; // It is no more required.
169 bool skipRead = false;
173 if (!xmlReader.Read ())
178 if (depth_ [nodeIndex] >= xmlReader.Depth) { // not ">=" ? But == worked when with ArrayList...
179 // if not, then current node is parent.
180 while (xmlReader.Depth <= depth_ [parent])
181 parent = parent_ [parent];
184 prevSibling = nodeIndex;
186 switch (xmlReader.NodeType) {
187 case XmlNodeType.Element:
188 case XmlNodeType.CDATA:
189 case XmlNodeType.SignificantWhitespace:
190 case XmlNodeType.Comment:
191 case XmlNodeType.Text:
192 case XmlNodeType.ProcessingInstruction:
193 if (requireFirstChildFill)
196 while (depth_ [prevSibling] != xmlReader.Depth)
197 prevSibling = parent_ [prevSibling];
198 if (prevSibling != 0)
199 position = position_ [prevSibling] + 1;
203 if (prevSibling != 0)
204 nextSibling_ [prevSibling] = nodeIndex;
205 if (requireFirstChildFill)
206 firstChild_ [nodeIndex-1] = nodeIndex;
208 case XmlNodeType.Whitespace:
209 if (xmlSpace == XmlSpace.Preserve)
210 goto case XmlNodeType.Text;
214 // No operations. Doctype, EntityReference,
218 requireFirstChildFill = false; // Might be changed in ProcessElement().
221 XPathNodeType nodeType = XPathNodeType.Text;
223 switch (xmlReader.NodeType) {
224 case XmlNodeType.Element:
225 ProcessElement (parent, prevSibling, position);
227 case XmlNodeType.EndElement:
229 case XmlNodeType.CDATA:
230 case XmlNodeType.SignificantWhitespace:
231 case XmlNodeType.Text:
242 xmlReader.IsEmptyElement,
243 xmlReader.LocalName, // for PI
244 xmlReader.NamespaceURI, // for PI
250 // this code is tricky, but after ReadString() invokation,
251 // xmlReader is moved to next node!!
253 value_ [nodeIndex] = xmlReader.ReadString ();
255 case XmlNodeType.Comment:
256 value = xmlReader.Value;
257 nodeType = XPathNodeType.Comment;
258 goto case XmlNodeType.Text;
259 case XmlNodeType.Whitespace:
260 goto case XmlNodeType.Text;
261 case XmlNodeType.ProcessingInstruction:
262 value = xmlReader.Value;
263 nodeType = XPathNodeType.ProcessingInstruction;
264 goto case XmlNodeType.Text;
268 private void ProcessElement (int parent, int previousSibling, int position)
270 int firstAttributeIndex = 0;
271 int lastNsIndexInCurrent = 0;
274 // process namespaces and attributes.
275 if (xmlReader.MoveToFirstAttribute ()) {
277 if (xmlReader.NamespaceURI == XmlNamespaces.XMLNS) {
278 // add namespace node.
281 nextNsNode_ [nsIndex] = lastNsIndexInCurrent == 0 ? namespaceNode_ [parent] : lastNsIndexInCurrent;
283 if (lastNsIndexInCurrent == 0)
284 namespaceNode_ [nodeIndex] = nsIndex;
285 this.AddNsNode (nodeIndex,
286 xmlReader.Prefix == "" ?
287 "" : xmlReader.LocalName,
289 lastNsIndexInCurrent = nsIndex;
291 // add attribute node.
293 this.AddAttribute (nodeIndex, xmlReader.LocalName, xmlReader.NamespaceURI, xmlReader.Prefix, xmlReader.Value, null);
294 if (firstAttributeIndex == 0)
295 firstAttributeIndex = attributeIndex;
297 nextAttribute_ [attributeIndex - 1] = attributeIndex;
298 // dummy for "current" attribute.
299 nextAttribute_ [attributeIndex] = 0;
301 } while (xmlReader.MoveToNextAttribute ());
302 xmlReader.MoveToElement ();
311 XPathNodeType.Element,
313 xmlReader.IsEmptyElement,
315 xmlReader.NamespaceURI,
317 "", // Element has no internal value.
321 if (!xmlReader.IsEmptyElement)
322 requireFirstChildFill = true;
325 private void SetObjectArrayLength (ref object [] a, int length)
327 object [] arr = new object [length];
328 Array.Copy (a, arr, System.Math.Min (a.Length, length));
332 private void SetBoolArrayLength (ref bool [] a, int length)
334 bool [] bArr = new bool [length];
335 Array.Copy (a, bArr, System.Math.Min (a.Length, length));
339 private void SetXPathNodeTypeArrayLength (ref XPathNodeType [] a, int length)
341 XPathNodeType [] arr = new XPathNodeType [length];
342 Array.Copy (a, arr, System.Math.Min (a.Length, length));
346 private void SetIntArrayLength (ref int [] a, int length)
348 int [] intArr = new int [length];
349 Array.Copy (a, intArr, System.Math.Min (a.Length, length));
353 private void SetStringArrayLength (ref string [] a, int length)
355 string [] strArr = new string [length];
356 Array.Copy (a, strArr, System.Math.Min (a.Length, length));
360 private void SetNodeArraysLength (int size)
362 SetIntArrayLength (ref firstChild_, size);
363 SetIntArrayLength (ref parent_, size);
364 SetIntArrayLength (ref firstAttribute_, size);
365 SetIntArrayLength (ref previousSibling_, size);
366 SetIntArrayLength (ref nextSibling_, size);
367 SetIntArrayLength (ref depth_, size);
368 SetIntArrayLength (ref position_, size);
369 SetXPathNodeTypeArrayLength (ref nodeType_, size);
370 SetStringArrayLength (ref baseUri_, size);
371 SetBoolArrayLength (ref isEmptyElement_, size);
372 SetStringArrayLength (ref localName_, size);
373 SetStringArrayLength (ref namespaceUri_, size);
374 SetStringArrayLength (ref prefix_, size);
375 SetStringArrayLength (ref value_, size);
376 SetStringArrayLength (ref xmlLang_, size);
377 SetIntArrayLength (ref namespaceNode_, size);
378 SetObjectArrayLength (ref schemaType_, size);
381 private void SetAttributeArraysLength (int size)
383 SetIntArrayLength (ref ownerElement_, size);
384 SetIntArrayLength (ref nextAttribute_, size);
385 SetStringArrayLength (ref attrLocalName_, size);
386 SetStringArrayLength (ref attrPrefix_, size);
387 SetStringArrayLength (ref attrNsUri_, size);
388 SetStringArrayLength (ref attrValue_, size);
389 SetObjectArrayLength (ref attrSchemaType_, size);
392 private void SetNsArraysLength (int size)
394 SetIntArrayLength (ref nsDeclaredElement_, size);
395 SetIntArrayLength (ref nextNsNode_, size);
396 SetStringArrayLength (ref nsNodeName_, size);
397 SetStringArrayLength (ref nsNodeUri_, size);
400 // Here followings are skipped: firstChild, nextSibling,
401 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, object schemaType)
403 if (firstChild_.Length < nodeIndex + 1) {
404 if (firstChild_.Length >= defaultCapacity)
405 defaultCapacity *= 2;
406 SetNodeArraysLength (defaultCapacity);
409 firstChild_ [nodeIndex] = 0; // dummy
410 parent_ [nodeIndex] = parent;
411 firstAttribute_ [nodeIndex] = firstAttribute;
412 previousSibling_ [nodeIndex] = previousSibling;
413 nextSibling_ [nodeIndex] = 0; // dummy
414 depth_ [nodeIndex] = depth;
415 position_ [nodeIndex] = position;
416 nodeType_ [nodeIndex] = nodeType;
417 baseUri_ [nodeIndex] = baseUri;
418 isEmptyElement_ [nodeIndex] = isEmptyElement;
419 localName_ [nodeIndex] = localName;
420 namespaceUri_ [nodeIndex] = ns;
421 prefix_ [nodeIndex] = prefix;
422 value_ [nodeIndex] = value;
423 xmlLang_ [nodeIndex] = xmlLang;
424 namespaceNode_ [nodeIndex] = namespaceNode;
425 schemaType_ [nodeIndex] = schemaType;
428 // Followings are skipped: nextAttribute,
429 public void AddAttribute (int ownerElement, string localName, string ns, string prefix, string value, object schemaType)
431 if (ownerElement_.Length < attributeIndex + 1) {
432 if (ownerElement_.Length >= defaultCapacity)
433 defaultCapacity *= 2;
434 SetAttributeArraysLength (defaultCapacity);
437 ownerElement_ [attributeIndex] = ownerElement;
438 attrLocalName_ [attributeIndex] = localName;
439 attrNsUri_ [attributeIndex] = ns;
440 attrPrefix_ [attributeIndex] = prefix;
441 attrValue_ [attributeIndex] = value;
442 attrSchemaType_ [attributeIndex] = schemaType;
445 // Followings are skipped: nextNsNode (may be next attribute in the same element, or ancestors' nsNode)
446 public void AddNsNode (int declaredElement, string name, string ns)
448 if (nsDeclaredElement_.Length < nsIndex + 1) {
449 if (nsDeclaredElement_.Length >= defaultCapacity)
450 defaultCapacity *= 2;
451 SetNsArraysLength (defaultCapacity);
454 nsDeclaredElement_ [nsIndex] = declaredElement;
455 nsNodeName_ [nsIndex] = name;
456 nsNodeUri_ [nsIndex] = ns;