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)
50 this.document = document;
53 // Copy constructor including position informations.
54 public DTMXPathNavigator2 (DTMXPathNavigator2 org)
56 document = org.document;
57 currentIsNode = org.currentIsNode;
58 currentIsAttr = org.currentIsAttr;
60 currentNode = org.currentNode;
61 currentAttr = org.currentAttr;
62 currentNs = org.currentNs;
65 XmlNameTable nameTable {
66 get { return document.NameTable; }
69 // Created XPathDocument. This is used to identify the origin of the navigator.
70 DTMXPathDocument2 document;
72 DTMXPathLinkedNode2 [] nodes {
73 get { return document.Nodes; }
75 DTMXPathAttributeNode2 [] attributes {
76 get { return document.Attributes; }
78 DTMXPathNamespaceNode2 [] namespaces {
79 get { return document.Namespaces; }
81 string [] atomicStringPool {
82 get { return document.AtomicStringPool; }
84 string [] nonAtomicStringPool {
85 get { return document.NonAtomicStringPool; }
90 get { return document.IdTable; }
102 public override string BaseURI {
103 get { return atomicStringPool [nodes [currentNode].BaseURI]; }
106 public override bool HasAttributes {
107 get { return currentIsNode ? nodes [currentNode].FirstAttribute != 0 : false; }
110 public override bool HasChildren {
111 get { return currentIsNode ? nodes [currentNode].FirstChild != 0 : false; }
114 public override bool IsEmptyElement {
115 get { return currentIsNode ? nodes [currentNode].IsEmptyElement : false; }
118 int IXmlLineInfo.LineNumber {
120 return currentIsAttr ? attributes [currentAttr].LineNumber :
121 nodes [currentNode].LineNumber;
125 int IXmlLineInfo.LinePosition {
127 return currentIsAttr ? attributes [currentAttr].LinePosition :
128 nodes [currentNode].LinePosition;
132 public override string LocalName {
135 return atomicStringPool [nodes [currentNode].LocalName];
136 else if (currentIsAttr)
137 return atomicStringPool [attributes [currentAttr].LocalName];
139 return atomicStringPool [namespaces [currentNs].Name];
143 // It maybe scarcely used, so I decided to compute it always.
144 public override string Name {
149 prefix = atomicStringPool [nodes [currentNode].Prefix];
150 localName = atomicStringPool [nodes [currentNode].LocalName];
151 } else if (currentIsAttr) {
152 prefix = atomicStringPool [attributes [currentAttr].Prefix];
153 localName = atomicStringPool [attributes [currentAttr].LocalName];
155 return atomicStringPool [namespaces [currentNs].Name];
158 return prefix + ':' + localName;
164 public override string NamespaceURI {
167 return atomicStringPool [nodes [currentNode].NamespaceURI];
169 return atomicStringPool [attributes [currentAttr].NamespaceURI];
174 public override XmlNameTable NameTable {
175 get { return nameTable; }
178 public override XPathNodeType NodeType {
181 return nodes [currentNode].NodeType;
182 else if (currentIsAttr)
183 return XPathNodeType.Attribute;
185 return XPathNodeType.Namespace;
189 public override string Prefix {
192 return atomicStringPool [nodes [currentNode].Prefix];
193 else if (currentIsAttr)
194 return atomicStringPool [attributes [currentAttr].Prefix];
199 public override string Value {
202 return nonAtomicStringPool [attributes [currentAttr].Value];
203 else if (!currentIsNode)
204 return atomicStringPool [namespaces [currentNs].Namespace];
206 switch (nodes [currentNode].NodeType) {
207 case XPathNodeType.Comment:
208 case XPathNodeType.ProcessingInstruction:
209 case XPathNodeType.Text:
210 case XPathNodeType.Whitespace:
211 case XPathNodeType.SignificantWhitespace:
212 return nonAtomicStringPool [nodes [currentNode].Value];
215 // Element - collect all content values
216 int iter = nodes [currentNode].FirstChild;
220 StringBuilder builder = null;
221 BuildValue (iter, ref builder);
222 return builder == null ? String.Empty : builder.ToString ();
226 void BuildValue (int iter, ref StringBuilder valueBuilder)
228 int end = nodes [currentNode].NextSibling;
230 int tmp = currentNode;
232 tmp = nodes [tmp].Parent;
233 end = nodes [tmp].NextSibling;
234 } while (end == 0 && tmp != 0);
240 switch (nodes [iter].NodeType) {
241 case XPathNodeType.Text:
242 case XPathNodeType.SignificantWhitespace:
243 case XPathNodeType.Whitespace:
244 if (valueBuilder == null)
245 valueBuilder = new StringBuilder ();
246 valueBuilder.Append (nonAtomicStringPool [nodes [iter].Value]);
253 public override string XmlLang {
254 get { return atomicStringPool [nodes [currentNode].XmlLang]; }
261 public override XPathNavigator Clone ()
263 return new DTMXPathNavigator2 (this);
266 public override XmlNodeOrder ComparePosition (XPathNavigator nav)
268 DTMXPathNavigator2 another = nav as DTMXPathNavigator2;
270 if (another == null || another.document != this.document)
271 return XmlNodeOrder.Unknown;
273 if (currentNode > another.currentNode)
274 return XmlNodeOrder.After;
275 else if (currentNode < another.currentNode)
276 return XmlNodeOrder.Before;
278 // another may attr or ns,
279 // and this may be also attr or ns.
280 if (another.currentIsAttr) {
281 if (this.currentIsAttr) {
282 if (currentAttr > another.currentAttr)
283 return XmlNodeOrder.After;
284 else if (currentAttr < another.currentAttr)
285 return XmlNodeOrder.Before;
287 return XmlNodeOrder.Same;
289 return XmlNodeOrder.Before;
290 } else if (!another.currentIsNode) {
291 if (!this.currentIsNode) {
292 if (currentNs > another.currentNs)
293 return XmlNodeOrder.After;
294 else if (currentNs < another.currentNs)
295 return XmlNodeOrder.Before;
297 return XmlNodeOrder.Same;
299 return XmlNodeOrder.Before;
301 return !another.currentIsNode ? XmlNodeOrder.Before : XmlNodeOrder.Same;
304 private int findAttribute (string localName, string namespaceURI)
306 if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
307 int cur = nodes [currentNode].FirstAttribute;
309 if (atomicStringPool [attributes [cur].LocalName] == localName && atomicStringPool [attributes [cur].NamespaceURI] == namespaceURI)
311 cur = attributes [cur].NextAttribute;
317 public override string GetAttribute (string localName,
320 int attr = findAttribute (localName, namespaceURI);
321 return (attr != 0) ? nonAtomicStringPool [attributes [attr].Value] : String.Empty;
324 public override string GetNamespace (string name)
326 if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
327 int nsNode = nodes [currentNode].FirstNamespace;
328 while (nsNode != 0) {
329 if (atomicStringPool [namespaces [nsNode].Name] == name)
330 return atomicStringPool [namespaces [nsNode].Namespace];
331 nsNode = namespaces [nsNode].NextNamespace;
337 bool IXmlLineInfo.HasLineInfo ()
342 public override bool IsDescendant (XPathNavigator nav)
344 DTMXPathNavigator2 another = nav as DTMXPathNavigator2;
346 if (another == null || another.document != this.document)
349 // Maybe we can improve here more efficiently by
350 // comparing node indices.
351 if (another.currentNode == currentNode)
352 return !another.currentIsNode;
353 int tmp = nodes [another.currentNode].Parent;
355 if (tmp == currentNode)
357 tmp = nodes [tmp].Parent;
362 public override bool IsSamePosition (XPathNavigator other)
364 DTMXPathNavigator2 another = other as DTMXPathNavigator2;
366 if (another == null || another.document != this.document)
369 if (this.currentNode != another.currentNode ||
370 this.currentIsAttr != another.currentIsAttr ||
371 this.currentIsNode != another.currentIsNode)
375 return this.currentAttr == another.currentAttr;
376 else if (!currentIsNode)
377 return this.currentNs == another.currentNs;
381 public override bool MoveTo (XPathNavigator other)
383 DTMXPathNavigator2 another = other as DTMXPathNavigator2;
385 if (another == null || another.document != this.document)
388 this.currentNode = another.currentNode;
389 this.currentAttr = another.currentAttr;
390 this.currentNs = another.currentNs;
391 this.currentIsNode = another.currentIsNode;
392 this.currentIsAttr = another.currentIsAttr;
396 public override bool MoveToAttribute (string localName,
399 int attr = findAttribute (localName, namespaceURI);
404 currentIsAttr = true;
405 currentIsNode = false;
409 public override bool MoveToFirst ()
414 int cur = nodes [currentNode].PreviousSibling;
421 next = nodes [cur].PreviousSibling;
424 currentIsNode = true;
428 public override bool MoveToFirstAttribute ()
433 int first = nodes [currentNode].FirstAttribute;
438 currentIsAttr = true;
439 currentIsNode = false;
443 public override bool MoveToFirstChild ()
448 int first = nodes [currentNode].FirstChild;
456 private bool moveToSpecifiedNamespace (int cur,
457 XPathNamespaceScope namespaceScope)
462 if (namespaceScope == XPathNamespaceScope.Local &&
463 namespaces [cur].DeclaredElement != currentNode)
466 if (namespaceScope != XPathNamespaceScope.All
467 && namespaces [cur].Namespace == XmlNamespaces.IndexXML)
471 moveToNamespace (cur);
478 public override bool MoveToFirstNamespace (
479 XPathNamespaceScope namespaceScope)
483 int cur = nodes [currentNode].FirstNamespace;
484 return moveToSpecifiedNamespace (cur, namespaceScope);
487 // Note that this support is extension to XPathDocument.
488 // XPathDocument does not support ID reference.
489 public override bool MoveToId (string id)
491 if (idTable.ContainsKey (id)) {
492 currentNode = (int) idTable [id];
493 currentIsNode = true;
494 currentIsAttr = false;
501 private void moveToNamespace (int nsNode)
503 currentIsNode = currentIsAttr = false;
507 public override bool MoveToNamespace (string name)
509 int cur = nodes [currentNode].FirstNamespace;
514 if (atomicStringPool [namespaces [cur].Name] == name) {
515 moveToNamespace (cur);
518 cur = namespaces [cur].NextNamespace;
523 public override bool MoveToNext ()
528 int next = nodes [currentNode].NextSibling;
532 currentIsNode = true;
536 public override bool MoveToNextAttribute ()
541 int next = attributes [currentAttr].NextAttribute;
548 public override bool MoveToNextNamespace (
549 XPathNamespaceScope namespaceScope)
551 if (currentIsAttr || currentIsNode)
554 int cur = namespaces [currentNs].NextNamespace;
555 return moveToSpecifiedNamespace (cur, namespaceScope);
558 public override bool MoveToParent ()
560 if (!currentIsNode) {
561 currentIsNode = true;
562 currentIsAttr = false;
566 int parent = nodes [currentNode].Parent;
567 if (parent == 0) // It is root itself.
570 currentNode = parent;
574 public override bool MoveToPrevious ()
579 int previous = nodes [currentNode].PreviousSibling;
582 currentNode = previous;
583 currentIsNode = true;
587 public override void MoveToRoot ()
589 currentNode = 1; // root is 1.
590 currentIsNode = true;
591 currentIsAttr = false;