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, false)
26 public DTMXPathDocumentBuilder (string url, XmlSpace space)
27 : this (url, space, false)
31 public DTMXPathDocumentBuilder (string url, XmlSpace space, bool supportID)
32 : this (new XmlTextReader (url), space, supportID)
36 public DTMXPathDocumentBuilder (XmlReader reader)
37 : this (reader, XmlSpace.None, false)
41 public DTMXPathDocumentBuilder (XmlReader reader, XmlSpace space)
42 : this (reader, space, false)
46 public DTMXPathDocumentBuilder (XmlReader reader, XmlSpace space, bool supportID)
48 this.xmlReader = reader;
50 this.validatingReader = reader as XmlValidatingReader;
51 this.xmlSpace = xmlSpace;
52 this.nameTable = reader.NameTable;
58 XmlValidatingReader validatingReader;
60 XmlNameTable nameTable;
61 int defaultCapacity = 100;
62 public int DefaultCapacity {
63 get { return defaultCapacity; }
66 throw new ArgumentOutOfRangeException ();
67 defaultCapacity = value;
71 #region Tree node info collections.
73 int [] firstChild_ = new int [0];
74 int [] parent_ = new int [0];
75 int [] firstAttribute_ = new int [0];
76 int [] previousSibling_ = new int [0];
77 int [] nextSibling_ = new int [0];
78 int [] depth_ = new int [0];
79 int [] position_ = new int [0];
80 XPathNodeType [] nodeType_ = new XPathNodeType [0];
81 string [] baseUri_ = new string [0];
82 bool [] isEmptyElement_ = new bool [0];
83 string [] localName_ = new string [0];
84 string [] namespaceUri_ = new string [0];
85 string [] prefix_ = new string [0];
86 string [] value_ = new string [0];
87 string [] xmlLang_ = new string [0];
88 int [] namespaceNode_ = new int [0];
89 object [] schemaType_ = new object [0];
92 int [] ownerElement_ = new int [0];
93 int [] nextAttribute_ = new int [0];
94 string [] attrLocalName_ = new string [0];
95 string [] attrPrefix_ = new string [0];
96 string [] attrNsUri_ = new string [0];
97 string [] attrValue_ = new string [0];
98 object [] attrSchemaType_ = new object [0];
101 int [] nsDeclaredElement_ = new int [100];
102 int [] nextNsNode_ = new int [100];
103 string [] nsNodeName_ = new string [100];
104 string [] nsNodeUri_ = new string [100];
106 // idTable [string value] -> int nodeId
113 bool requireFirstChildFill;
115 public DTMXPathDocument CreateDocument ()
117 return new DTMXPathDocument (nameTable,
154 public void Compile ()
156 idTable_ = new Hashtable ();
158 // index 0 is dummy. No node (including Root) is assigned to this index
159 // So that we can easily compare index != 0 instead of index < 0.
160 // (Difference between jnz or jbe in 80x86.)
161 AddNode (0, 0, 0, 0, 0, 0, XPathNodeType.All, "", false, "", "", "", "", "", 0, null);
163 AddAttribute (0, null, null, null, null, null);
164 nextAttribute_ [0] = 0;
165 AddNsNode (0, null, null);
168 AddNsNode (1, "xml", XmlNamespaces.XML);
172 AddNode (0, 0, 0, 0, -1, 0, XPathNodeType.Root, xmlReader.BaseURI, false, "", "", "", "", "", 1, null);
175 this.requireFirstChildFill = true;
177 while (!xmlReader.EOF)
179 SetNodeArraysLength (nodeIndex + 1);
180 SetAttributeArraysLength (attributeIndex + 1);
181 SetNsArraysLength (nsIndex + 1);
183 xmlReader = null; // It is no more required.
188 bool skipRead = false;
193 if (!xmlReader.Read ())
196 int parent = nodeIndex;
198 if (depth_ [nodeIndex] >= xmlReader.Depth) { // not ">=" ? But == worked when with ArrayList...
199 // if not, then current node is parent.
200 while (xmlReader.Depth <= depth_ [parent])
201 parent = parent_ [parent];
204 prevSibling = nodeIndex;
206 switch (xmlReader.NodeType) {
207 case XmlNodeType.Element:
208 case XmlNodeType.CDATA:
209 case XmlNodeType.SignificantWhitespace:
210 case XmlNodeType.Comment:
211 case XmlNodeType.Text:
212 case XmlNodeType.ProcessingInstruction:
213 if (requireFirstChildFill)
216 while (depth_ [prevSibling] != xmlReader.Depth)
217 prevSibling = parent_ [prevSibling];
218 if (prevSibling != 0)
219 position = position_ [prevSibling] + 1;
223 if (prevSibling != 0)
224 nextSibling_ [prevSibling] = nodeIndex;
225 if (requireFirstChildFill)
226 firstChild_ [parent] = nodeIndex;
228 case XmlNodeType.Whitespace:
229 if (xmlSpace == XmlSpace.Preserve)
230 goto case XmlNodeType.Text;
233 case XmlNodeType.EndElement:
234 requireFirstChildFill = false;
237 // No operations. Doctype, EntityReference,
241 requireFirstChildFill = false; // Might be changed in ProcessElement().
244 XPathNodeType nodeType = XPathNodeType.Text;
246 switch (xmlReader.NodeType) {
247 case XmlNodeType.Element:
248 ProcessElement (parent, prevSibling, position);
250 case XmlNodeType.CDATA:
251 case XmlNodeType.SignificantWhitespace:
252 case XmlNodeType.Text:
263 xmlReader.IsEmptyElement,
264 xmlReader.LocalName, // for PI
265 xmlReader.NamespaceURI, // for PI
271 // this code is tricky, but after ReadString() invokation,
272 // xmlReader is moved to next node!!
274 value_ [nodeIndex] = xmlReader.ReadString ();
276 case XmlNodeType.Comment:
277 value = xmlReader.Value;
278 nodeType = XPathNodeType.Comment;
279 goto case XmlNodeType.Text;
280 case XmlNodeType.Whitespace:
281 goto case XmlNodeType.Text;
282 case XmlNodeType.ProcessingInstruction:
283 value = xmlReader.Value;
284 nodeType = XPathNodeType.ProcessingInstruction;
285 goto case XmlNodeType.Text;
289 private void ProcessElement (int parent, int previousSibling, int position)
291 int firstAttributeIndex = 0;
292 int lastNsIndexInCurrent = 0;
295 // process namespaces and attributes.
296 if (xmlReader.MoveToFirstAttribute ()) {
298 if (xmlReader.NamespaceURI == XmlNamespaces.XMLNS) {
299 // add namespace node.
302 nextNsNode_ [nsIndex] = lastNsIndexInCurrent == 0 ? namespaceNode_ [parent] : lastNsIndexInCurrent;
304 if (lastNsIndexInCurrent == 0)
305 namespaceNode_ [nodeIndex] = nsIndex;
306 this.AddNsNode (nodeIndex,
307 (xmlReader.Prefix == null || xmlReader.Prefix == String.Empty) ?
308 "" : xmlReader.LocalName,
310 lastNsIndexInCurrent = nsIndex;
312 // add attribute node.
314 this.AddAttribute (nodeIndex, xmlReader.LocalName, xmlReader.NamespaceURI, xmlReader.Prefix != null ? xmlReader.Prefix : String.Empty, xmlReader.Value, null);
315 if (firstAttributeIndex == 0)
316 firstAttributeIndex = attributeIndex;
318 nextAttribute_ [attributeIndex - 1] = attributeIndex;
319 // dummy for "current" attribute.
320 nextAttribute_ [attributeIndex] = 0;
323 if (validatingReader != null) {
324 XmlSchemaDatatype dt = validatingReader.SchemaType as XmlSchemaDatatype;
326 XmlSchemaType xsType = validatingReader.SchemaType as XmlSchemaType;
327 dt = xsType.Datatype;
329 if (dt != null && dt.TokenizedType == XmlTokenizedType.ID)
330 idTable_.Add (xmlReader.Value, nodeIndex);
333 } while (xmlReader.MoveToNextAttribute ());
334 xmlReader.MoveToElement ();
343 XPathNodeType.Element,
345 xmlReader.IsEmptyElement,
347 xmlReader.NamespaceURI,
349 "", // Element has no internal value.
353 if (!xmlReader.IsEmptyElement)
354 requireFirstChildFill = true;
357 private void SetObjectArrayLength (ref object [] a, int length)
359 object [] arr = new object [length];
360 Array.Copy (a, arr, System.Math.Min (a.Length, length));
364 private void SetBoolArrayLength (ref bool [] a, int length)
366 bool [] bArr = new bool [length];
367 Array.Copy (a, bArr, System.Math.Min (a.Length, length));
371 private void SetXPathNodeTypeArrayLength (ref XPathNodeType [] a, int length)
373 XPathNodeType [] arr = new XPathNodeType [length];
374 Array.Copy (a, arr, System.Math.Min (a.Length, length));
378 private void SetIntArrayLength (ref int [] a, int length)
380 int [] intArr = new int [length];
381 Array.Copy (a, intArr, System.Math.Min (a.Length, length));
385 private void SetStringArrayLength (ref string [] a, int length)
387 string [] strArr = new string [length];
388 Array.Copy (a, strArr, System.Math.Min (a.Length, length));
392 private void SetNodeArraysLength (int size)
394 SetIntArrayLength (ref firstChild_, size);
395 SetIntArrayLength (ref parent_, size);
396 SetIntArrayLength (ref firstAttribute_, size);
397 SetIntArrayLength (ref previousSibling_, size);
398 SetIntArrayLength (ref nextSibling_, size);
399 SetIntArrayLength (ref depth_, size);
400 SetIntArrayLength (ref position_, size);
401 SetXPathNodeTypeArrayLength (ref nodeType_, size);
402 SetStringArrayLength (ref baseUri_, size);
403 SetBoolArrayLength (ref isEmptyElement_, size);
404 SetStringArrayLength (ref localName_, size);
405 SetStringArrayLength (ref namespaceUri_, size);
406 SetStringArrayLength (ref prefix_, size);
407 SetStringArrayLength (ref value_, size);
408 SetStringArrayLength (ref xmlLang_, size);
409 SetIntArrayLength (ref namespaceNode_, size);
410 SetObjectArrayLength (ref schemaType_, size);
413 private void SetAttributeArraysLength (int size)
415 SetIntArrayLength (ref ownerElement_, size);
416 SetIntArrayLength (ref nextAttribute_, size);
417 SetStringArrayLength (ref attrLocalName_, size);
418 SetStringArrayLength (ref attrPrefix_, size);
419 SetStringArrayLength (ref attrNsUri_, size);
420 SetStringArrayLength (ref attrValue_, size);
421 SetObjectArrayLength (ref attrSchemaType_, size);
424 private void SetNsArraysLength (int size)
426 SetIntArrayLength (ref nsDeclaredElement_, size);
427 SetIntArrayLength (ref nextNsNode_, size);
428 SetStringArrayLength (ref nsNodeName_, size);
429 SetStringArrayLength (ref nsNodeUri_, size);
432 // Here followings are skipped: firstChild, nextSibling,
433 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)
435 if (firstChild_.Length < nodeIndex + 1) {
436 if (firstChild_.Length >= defaultCapacity)
437 defaultCapacity *= 2;
438 SetNodeArraysLength (defaultCapacity);
441 firstChild_ [nodeIndex] = 0; // dummy
442 parent_ [nodeIndex] = parent;
443 firstAttribute_ [nodeIndex] = firstAttribute;
444 previousSibling_ [nodeIndex] = previousSibling;
445 nextSibling_ [nodeIndex] = 0; // dummy
446 depth_ [nodeIndex] = depth;
447 position_ [nodeIndex] = position;
448 nodeType_ [nodeIndex] = nodeType;
449 baseUri_ [nodeIndex] = baseUri;
450 isEmptyElement_ [nodeIndex] = isEmptyElement;
451 localName_ [nodeIndex] = localName;
452 namespaceUri_ [nodeIndex] = ns;
453 prefix_ [nodeIndex] = prefix;
454 value_ [nodeIndex] = value;
455 xmlLang_ [nodeIndex] = xmlLang;
456 namespaceNode_ [nodeIndex] = namespaceNode;
457 schemaType_ [nodeIndex] = schemaType;
460 // Followings are skipped: nextAttribute,
461 public void AddAttribute (int ownerElement, string localName, string ns, string prefix, string value, object schemaType)
463 if (ownerElement_.Length < attributeIndex + 1) {
464 if (ownerElement_.Length >= defaultCapacity)
465 defaultCapacity *= 2;
466 SetAttributeArraysLength (defaultCapacity);
469 ownerElement_ [attributeIndex] = ownerElement;
470 attrLocalName_ [attributeIndex] = localName;
471 attrNsUri_ [attributeIndex] = ns;
472 attrPrefix_ [attributeIndex] = prefix;
473 attrValue_ [attributeIndex] = value;
474 attrSchemaType_ [attributeIndex] = schemaType;
477 // Followings are skipped: nextNsNode (may be next attribute in the same element, or ancestors' nsNode)
478 public void AddNsNode (int declaredElement, string name, string ns)
480 if (nsDeclaredElement_.Length < nsIndex + 1) {
481 if (nsDeclaredElement_.Length >= defaultCapacity)
482 defaultCapacity *= 2;
483 SetNsArraysLength (defaultCapacity);
486 nsDeclaredElement_ [nsIndex] = declaredElement;
487 nsNodeName_ [nsIndex] = name;
488 nsNodeUri_ [nsIndex] = ns;