2 // Mono.Xml.XPath.DTMXPathNavigator2
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // (C) 2004 Novell Inc.
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
34 using System.Xml.Schema;
35 using System.Xml.XPath;
37 namespace Mono.Xml.XPath
39 #if OUTSIDE_SYSTEM_XML
44 class DTMXPathNavigator2 : XPathNavigator, IXmlLineInfo
47 public DTMXPathNavigator2 (DTMXPathDocument2 document,
48 XmlNameTable nameTable,
49 DTMXPathLinkedNode2 [] nodes,
50 DTMXPathAttributeNode2 [] attributes,
51 DTMXPathNamespaceNode2 [] namespaces,
52 string [] atomicStringPool,
53 string [] nonAtomicStringPool,
57 this.attributes = attributes;
58 this.namespaces = namespaces;
59 this.atomicStringPool = atomicStringPool;
60 this.nonAtomicStringPool = nonAtomicStringPool;
61 this.idTable = idTable;
62 this.nameTable = nameTable;
64 this.document = document;
67 // Copy constructor including position informations.
68 public DTMXPathNavigator2 (DTMXPathNavigator2 org)
69 : this (org.document, org.nameTable,
70 org.nodes, org.attributes, org.namespaces,
71 org.atomicStringPool, org.nonAtomicStringPool,
74 currentIsNode = org.currentIsNode;
75 currentIsAttr = org.currentIsAttr;
77 currentNode = org.currentNode;
78 currentAttr = org.currentAttr;
79 currentNs = org.currentNs;
82 XmlNameTable nameTable;
84 // Created XPathDocument. This is used to identify the origin of the navigator.
85 DTMXPathDocument2 document;
87 DTMXPathLinkedNode2 [] nodes;// = new DTMXPathLinkedNode [0];
88 DTMXPathAttributeNode2 [] attributes;// = new DTMXPathAttributeNode [0];
89 DTMXPathNamespaceNode2 [] namespaces;// = new DTMXPathNamespaceNode [0];
92 string [] atomicStringPool;
93 string [] nonAtomicStringPool;
105 StringBuilder valueBuilder;
109 internal DTMXPathNavigator2 (XmlNameTable nt)
118 public override string BaseURI {
119 get { return atomicStringPool [nodes [currentNode].BaseURI]; }
122 public override bool HasAttributes {
123 get { return currentIsNode ? nodes [currentNode].FirstAttribute != 0 : false; }
126 public override bool HasChildren {
127 get { return currentIsNode ? nodes [currentNode].FirstChild != 0 : false; }
130 public override bool IsEmptyElement {
131 get { return currentIsNode ? nodes [currentNode].IsEmptyElement : false; }
134 int IXmlLineInfo.LineNumber {
136 return currentIsAttr ? attributes [currentAttr].LineNumber :
137 nodes [currentNode].LineNumber;
141 int IXmlLineInfo.LinePosition {
143 return currentIsAttr ? attributes [currentAttr].LinePosition :
144 nodes [currentNode].LinePosition;
148 public override string LocalName {
151 return atomicStringPool [nodes [currentNode].LocalName];
152 else if (currentIsAttr)
153 return atomicStringPool [attributes [currentAttr].LocalName];
155 return atomicStringPool [namespaces [currentNs].Name];
159 // It maybe scarcely used, so I decided to compute it always.
160 public override string Name {
165 prefix = atomicStringPool [nodes [currentNode].Prefix];
166 localName = atomicStringPool [nodes [currentNode].LocalName];
167 } else if (currentIsAttr) {
168 prefix = atomicStringPool [attributes [currentAttr].Prefix];
169 localName = atomicStringPool [attributes [currentAttr].LocalName];
171 return atomicStringPool [namespaces [currentNs].Name];
174 return prefix + ':' + localName;
180 public override string NamespaceURI {
183 return atomicStringPool [nodes [currentNode].NamespaceURI];
185 return atomicStringPool [attributes [currentAttr].NamespaceURI];
190 public override XmlNameTable NameTable {
191 get { return nameTable; }
194 public override XPathNodeType NodeType {
197 return nodes [currentNode].NodeType;
198 else if (currentIsAttr)
199 return XPathNodeType.Attribute;
201 return XPathNodeType.Namespace;
205 public override string Prefix {
208 return atomicStringPool [nodes [currentNode].Prefix];
209 else if (currentIsAttr)
210 return atomicStringPool [attributes [currentAttr].Prefix];
215 public override string Value {
218 return nonAtomicStringPool [attributes [currentAttr].Value];
219 else if (!currentIsNode)
220 return atomicStringPool [namespaces [currentNs].Namespace];
222 switch (nodes [currentNode].NodeType) {
223 case XPathNodeType.Comment:
224 case XPathNodeType.ProcessingInstruction:
225 case XPathNodeType.Text:
226 case XPathNodeType.Whitespace:
227 case XPathNodeType.SignificantWhitespace:
228 return nonAtomicStringPool [nodes [currentNode].Value];
231 // Element - collect all content values
232 int iter = nodes [currentNode].FirstChild;
236 if (valueBuilder == null)
237 valueBuilder = new StringBuilder ();
239 valueBuilder.Length = 0;
241 int end = nodes [currentNode].NextSibling;
243 int tmp = currentNode;
245 tmp = nodes [tmp].Parent;
246 end = nodes [tmp].NextSibling;
247 } while (end == 0 && tmp != 0);
253 switch (nodes [iter].NodeType) {
254 case XPathNodeType.Text:
255 case XPathNodeType.SignificantWhitespace:
256 case XPathNodeType.Whitespace:
257 valueBuilder.Append (nonAtomicStringPool [nodes [iter].Value]);
263 return valueBuilder.ToString ();
267 public override string XmlLang {
268 get { return atomicStringPool [nodes [currentNode].XmlLang]; }
275 public override XPathNavigator Clone ()
277 return new DTMXPathNavigator2 (this);
280 public override XmlNodeOrder ComparePosition (XPathNavigator nav)
282 DTMXPathNavigator2 another = nav as DTMXPathNavigator2;
284 if (another == null || another.document != this.document)
285 return XmlNodeOrder.Unknown;
287 if (currentNode > another.currentNode)
288 return XmlNodeOrder.After;
289 else if (currentNode < another.currentNode)
290 return XmlNodeOrder.Before;
292 // another may attr or ns,
293 // and this may be also attr or ns.
294 if (another.currentIsAttr) {
295 if (this.currentIsAttr) {
296 if (currentAttr > another.currentAttr)
297 return XmlNodeOrder.After;
298 else if (currentAttr < another.currentAttr)
299 return XmlNodeOrder.Before;
301 return XmlNodeOrder.Same;
303 return XmlNodeOrder.Before;
304 } else if (!another.currentIsNode) {
305 if (!this.currentIsNode) {
306 if (currentNs > another.currentNs)
307 return XmlNodeOrder.After;
308 else if (currentNs < another.currentNs)
309 return XmlNodeOrder.Before;
311 return XmlNodeOrder.Same;
313 return XmlNodeOrder.Before;
315 return !another.currentIsNode ? XmlNodeOrder.Before : XmlNodeOrder.Same;
318 private int findAttribute (string localName, string namespaceURI)
320 if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
321 int cur = nodes [currentNode].FirstAttribute;
323 if (atomicStringPool [attributes [cur].LocalName] == localName && atomicStringPool [attributes [cur].NamespaceURI] == namespaceURI)
325 cur = attributes [cur].NextAttribute;
331 public override string GetAttribute (string localName,
334 int attr = findAttribute (localName, namespaceURI);
335 return (attr != 0) ? nonAtomicStringPool [attributes [attr].Value] : String.Empty;
338 public override string GetNamespace (string name)
340 if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
341 int nsNode = nodes [currentNode].FirstNamespace;
342 while (nsNode != 0) {
343 if (atomicStringPool [namespaces [nsNode].Name] == name)
344 return atomicStringPool [namespaces [nsNode].Namespace];
345 nsNode = namespaces [nsNode].NextNamespace;
351 bool IXmlLineInfo.HasLineInfo ()
356 public override bool IsDescendant (XPathNavigator nav)
358 DTMXPathNavigator2 another = nav as DTMXPathNavigator2;
360 if (another == null || another.document != this.document)
363 // Maybe we can improve here more efficiently by
364 // comparing node indices.
365 if (another.currentNode == currentNode)
366 return !another.currentIsNode;
367 int tmp = nodes [another.currentNode].Parent;
369 if (tmp == currentNode)
371 tmp = nodes [tmp].Parent;
376 public override bool IsSamePosition (XPathNavigator other)
378 DTMXPathNavigator2 another = other as DTMXPathNavigator2;
380 if (another == null || another.document != this.document)
383 if (this.currentNode != another.currentNode ||
384 this.currentIsAttr != another.currentIsAttr ||
385 this.currentIsNode != another.currentIsNode)
389 return this.currentAttr == another.currentAttr;
390 else if (!currentIsNode)
391 return this.currentNs == another.currentNs;
395 public override bool MoveTo (XPathNavigator other)
397 DTMXPathNavigator2 another = other as DTMXPathNavigator2;
399 if (another == null || another.document != this.document)
402 this.currentNode = another.currentNode;
403 this.currentAttr = another.currentAttr;
404 this.currentNs = another.currentNs;
405 this.currentIsNode = another.currentIsNode;
406 this.currentIsAttr = another.currentIsAttr;
410 public override bool MoveToAttribute (string localName,
413 int attr = findAttribute (localName, namespaceURI);
418 currentIsAttr = true;
419 currentIsNode = false;
423 public override bool MoveToFirst ()
428 int cur = nodes [currentNode].PreviousSibling;
435 next = nodes [cur].PreviousSibling;
438 currentIsNode = true;
442 public override bool MoveToFirstAttribute ()
447 int first = nodes [currentNode].FirstAttribute;
452 currentIsAttr = true;
453 currentIsNode = false;
457 public override bool MoveToFirstChild ()
462 int first = nodes [currentNode].FirstChild;
470 private bool moveToSpecifiedNamespace (int cur,
471 XPathNamespaceScope namespaceScope)
476 if (namespaceScope == XPathNamespaceScope.Local &&
477 namespaces [cur].DeclaredElement != currentNode)
480 if (namespaceScope != XPathNamespaceScope.All
481 && namespaces [cur].Namespace == XmlNamespaces.IndexXML)
485 moveToNamespace (cur);
492 public override bool MoveToFirstNamespace (
493 XPathNamespaceScope namespaceScope)
497 int cur = nodes [currentNode].FirstNamespace;
498 return moveToSpecifiedNamespace (cur, namespaceScope);
501 // Note that this support is extension to XPathDocument.
502 // XPathDocument does not support ID reference.
503 public override bool MoveToId (string id)
505 if (idTable.ContainsKey (id)) {
506 currentNode = (int) idTable [id];
507 currentIsNode = true;
508 currentIsAttr = false;
515 private void moveToNamespace (int nsNode)
517 currentIsNode = currentIsAttr = false;
521 public override bool MoveToNamespace (string name)
523 int cur = nodes [currentNode].FirstNamespace;
528 if (atomicStringPool [namespaces [cur].Name] == name) {
529 moveToNamespace (cur);
532 cur = namespaces [cur].NextNamespace;
537 public override bool MoveToNext ()
542 int next = nodes [currentNode].NextSibling;
546 currentIsNode = true;
550 public override bool MoveToNextAttribute ()
555 int next = attributes [currentAttr].NextAttribute;
562 public override bool MoveToNextNamespace (
563 XPathNamespaceScope namespaceScope)
565 if (currentIsAttr || currentIsNode)
568 int cur = namespaces [currentNs].NextNamespace;
569 return moveToSpecifiedNamespace (cur, namespaceScope);
572 public override bool MoveToParent ()
574 if (!currentIsNode) {
575 currentIsNode = true;
576 currentIsAttr = false;
580 int parent = nodes [currentNode].Parent;
581 if (parent == 0) // It is root itself.
584 currentNode = parent;
588 public override bool MoveToPrevious ()
593 int previous = nodes [currentNode].PreviousSibling;
596 currentNode = previous;
597 currentIsNode = true;
601 public override void MoveToRoot ()
603 currentNode = 1; // root is 1.
604 currentIsNode = true;
605 currentIsAttr = false;