2 // Mono.Xml.XPath.DTMXPathNavigator
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C) 2003 Atsushi Enomoto
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 DTMXPathNavigator : XPathNavigator, IXmlLineInfo
47 public DTMXPathNavigator (DTMXPathDocument document,
48 XmlNameTable nameTable,
49 DTMXPathLinkedNode [] nodes,
50 DTMXPathAttributeNode [] attributes,
51 DTMXPathNamespaceNode [] namespaces,
55 this.attributes = attributes;
56 this.namespaces = namespaces;
57 this.idTable = idTable;
58 this.nameTable = nameTable;
60 this.document = document;
63 // Copy constructor including position informations.
64 public DTMXPathNavigator (DTMXPathNavigator org)
65 : this (org.document, org.nameTable,
66 org.nodes, org.attributes, org.namespaces,
69 currentIsNode = org.currentIsNode;
70 currentIsAttr = org.currentIsAttr;
72 currentNode = org.currentNode;
73 currentAttr = org.currentAttr;
74 currentNs = org.currentNs;
77 XmlNameTable nameTable;
79 // Created XPathDocument. This is used to identify the origin of the navigator.
80 DTMXPathDocument document;
82 DTMXPathLinkedNode [] nodes;// = new DTMXPathLinkedNode [0];
83 DTMXPathAttributeNode [] attributes;// = new DTMXPathAttributeNode [0];
84 DTMXPathNamespaceNode [] namespaces;// = new DTMXPathNamespaceNode [0];
96 StringBuilder valueBuilder;
100 internal DTMXPathNavigator (XmlNameTable nt)
109 public override string BaseURI {
110 get { return nodes [currentNode].BaseURI; }
113 public override bool HasAttributes {
114 get { return currentIsNode ? nodes [currentNode].FirstAttribute != 0 : false; }
117 public override bool HasChildren {
118 get { return currentIsNode ? nodes [currentNode].FirstChild != 0 : false; }
121 public override bool IsEmptyElement {
122 get { return currentIsNode ? nodes [currentNode].IsEmptyElement : false; }
125 int IXmlLineInfo.LineNumber {
127 return currentIsAttr ? attributes [currentAttr].LineNumber :
128 nodes [currentNode].LineNumber;
132 int IXmlLineInfo.LinePosition {
134 return currentIsAttr ? attributes [currentAttr].LinePosition :
135 nodes [currentNode].LinePosition;
139 public override string LocalName {
142 return nodes [currentNode].LocalName;
143 else if (currentIsAttr)
144 return attributes [currentAttr].LocalName;
146 return namespaces [currentNs].Name;
150 // It maybe scarcely used, so I decided to compute it always.
151 public override string Name {
156 prefix = nodes [currentNode].Prefix;
157 localName = nodes [currentNode].LocalName;
158 } else if (currentIsAttr) {
159 prefix = attributes [currentAttr].Prefix;
160 localName = attributes [currentAttr].LocalName;
162 return namespaces [currentNs].Name;
165 return prefix + ':' + localName;
171 public override string NamespaceURI {
174 return nodes [currentNode].NamespaceURI;
176 return attributes [currentAttr].NamespaceURI;
181 public override XmlNameTable NameTable {
182 get { return nameTable; }
185 public override XPathNodeType NodeType {
188 return nodes [currentNode].NodeType;
189 else if (currentIsAttr)
190 return XPathNodeType.Attribute;
192 return XPathNodeType.Namespace;
196 public override string Prefix {
199 return nodes [currentNode].Prefix;
200 else if (currentIsAttr)
201 return attributes [currentAttr].Prefix;
206 public override string Value {
209 return attributes [currentAttr].Value;
210 else if (!currentIsNode)
211 return namespaces [currentNs].Namespace;
213 switch (nodes [currentNode].NodeType) {
214 case XPathNodeType.Comment:
215 case XPathNodeType.ProcessingInstruction:
216 case XPathNodeType.Text:
217 case XPathNodeType.Whitespace:
218 case XPathNodeType.SignificantWhitespace:
219 return nodes [currentNode].Value;
222 // Element - collect all content values
223 int iter = nodes [currentNode].FirstChild;
227 if (valueBuilder == null)
228 valueBuilder = new StringBuilder ();
230 valueBuilder.Length = 0;
232 int end = nodes [currentNode].NextSibling;
234 int tmp = currentNode;
236 tmp = nodes [tmp].Parent;
237 end = nodes [tmp].NextSibling;
238 } while (end == 0 && tmp != 0);
244 switch (nodes [iter].NodeType) {
245 case XPathNodeType.Text:
246 case XPathNodeType.SignificantWhitespace:
247 case XPathNodeType.Whitespace:
248 valueBuilder.Append (nodes [iter].Value);
254 return valueBuilder.ToString ();
258 public override string XmlLang {
259 get { return nodes [currentNode].XmlLang; }
266 public override XPathNavigator Clone ()
268 return new DTMXPathNavigator (this);
271 public override XmlNodeOrder ComparePosition (XPathNavigator nav)
273 DTMXPathNavigator another = nav as DTMXPathNavigator;
275 if (another == null || another.document != this.document)
276 return XmlNodeOrder.Unknown;
278 if (currentNode > another.currentNode)
279 return XmlNodeOrder.After;
280 else if (currentNode < another.currentNode)
281 return XmlNodeOrder.Before;
283 // another may attr or ns,
284 // and this may be also attr or ns.
285 if (another.currentIsAttr) {
286 if (this.currentIsAttr) {
287 if (currentAttr > another.currentAttr)
288 return XmlNodeOrder.After;
289 else if (currentAttr < another.currentAttr)
290 return XmlNodeOrder.Before;
292 return XmlNodeOrder.Same;
294 return XmlNodeOrder.Before;
295 } else if (!another.currentIsNode) {
296 if (!this.currentIsNode) {
297 if (currentNs > another.currentNs)
298 return XmlNodeOrder.After;
299 else if (currentNs < another.currentNs)
300 return XmlNodeOrder.Before;
302 return XmlNodeOrder.Same;
304 return XmlNodeOrder.Before;
306 return !another.currentIsNode ? XmlNodeOrder.Before : XmlNodeOrder.Same;
309 private int findAttribute (string localName, string namespaceURI)
311 if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
312 int cur = nodes [currentNode].FirstAttribute;
314 if (attributes [cur].LocalName == localName && attributes [cur].NamespaceURI == namespaceURI)
316 cur = attributes [cur].NextAttribute;
322 public override string GetAttribute (string localName,
325 int attr = findAttribute (localName, namespaceURI);
326 return (attr != 0) ? attributes [attr].Value : String.Empty;
329 public override string GetNamespace (string name)
331 if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
332 int nsNode = nodes [currentNode].FirstNamespace;
333 while (nsNode != 0) {
334 if (namespaces [nsNode].Name == name)
335 return namespaces [nsNode].Namespace;
336 nsNode = namespaces [nsNode].NextNamespace;
342 bool IXmlLineInfo.HasLineInfo ()
347 public override bool IsDescendant (XPathNavigator nav)
349 DTMXPathNavigator another = nav as DTMXPathNavigator;
351 if (another == null || another.document != this.document)
354 // Maybe we can improve here more efficiently by
355 // comparing node indices.
356 if (another.currentNode == currentNode)
357 return !another.currentIsNode;
358 int tmp = nodes [another.currentNode].Parent;
360 if (tmp == currentNode)
362 tmp = nodes [tmp].Parent;
367 public override bool IsSamePosition (XPathNavigator other)
369 DTMXPathNavigator another = other as DTMXPathNavigator;
371 if (another == null || another.document != this.document)
374 if (this.currentNode != another.currentNode ||
375 this.currentIsAttr != another.currentIsAttr ||
376 this.currentIsNode != another.currentIsNode)
380 return this.currentAttr == another.currentAttr;
381 else if (!currentIsNode)
382 return this.currentNs == another.currentNs;
386 public override bool MoveTo (XPathNavigator other)
388 DTMXPathNavigator another = other as DTMXPathNavigator;
390 if (another == null || another.document != this.document)
393 this.currentNode = another.currentNode;
394 this.currentAttr = another.currentAttr;
395 this.currentNs = another.currentNs;
396 this.currentIsNode = another.currentIsNode;
397 this.currentIsAttr = another.currentIsAttr;
401 public override bool MoveToAttribute (string localName,
404 int attr = findAttribute (localName, namespaceURI);
409 currentIsAttr = true;
410 currentIsNode = false;
414 public override bool MoveToFirst ()
419 int cur = nodes [currentNode].PreviousSibling;
426 next = nodes [cur].PreviousSibling;
429 currentIsNode = true;
433 public override bool MoveToFirstAttribute ()
438 int first = nodes [currentNode].FirstAttribute;
443 currentIsAttr = true;
444 currentIsNode = false;
448 public override bool MoveToFirstChild ()
453 int first = nodes [currentNode].FirstChild;
461 private bool moveToSpecifiedNamespace (int cur,
462 XPathNamespaceScope namespaceScope)
467 if (namespaceScope == XPathNamespaceScope.Local &&
468 namespaces [cur].DeclaredElement != currentNode)
471 if (namespaceScope != XPathNamespaceScope.All
472 && namespaces [cur].Namespace == XmlNamespaces.XML)
476 moveToNamespace (cur);
483 public override bool MoveToFirstNamespace (
484 XPathNamespaceScope namespaceScope)
488 int cur = nodes [currentNode].FirstNamespace;
489 return moveToSpecifiedNamespace (cur, namespaceScope);
492 // Note that this support is extension to XPathDocument.
493 // XPathDocument does not support ID reference.
494 public override bool MoveToId (string id)
496 if (idTable.ContainsKey (id)) {
497 currentNode = (int) idTable [id];
498 currentIsNode = true;
499 currentIsAttr = false;
506 private void moveToNamespace (int nsNode)
508 currentIsNode = currentIsAttr = false;
512 public override bool MoveToNamespace (string name)
514 int cur = nodes [currentNode].FirstNamespace;
519 if (namespaces [cur].Name == name) {
520 moveToNamespace (cur);
523 cur = namespaces [cur].NextNamespace;
528 public override bool MoveToNext ()
533 int next = nodes [currentNode].NextSibling;
537 currentIsNode = true;
541 public override bool MoveToNextAttribute ()
546 int next = attributes [currentAttr].NextAttribute;
553 public override bool MoveToNextNamespace (
554 XPathNamespaceScope namespaceScope)
556 if (currentIsAttr || currentIsNode)
559 int cur = namespaces [currentNs].NextNamespace;
560 return moveToSpecifiedNamespace (cur, namespaceScope);
563 public override bool MoveToParent ()
565 if (!currentIsNode) {
566 currentIsNode = true;
567 currentIsAttr = false;
571 int parent = nodes [currentNode].Parent;
572 if (parent == 0) // It is root itself.
575 currentNode = parent;
579 public override bool MoveToPrevious ()
584 int previous = nodes [currentNode].PreviousSibling;
587 currentNode = previous;
588 currentIsNode = true;
592 public override void MoveToRoot ()
594 currentNode = 1; // root is 1.
595 currentIsNode = true;
596 currentIsAttr = false;
604 public const string XML = "http://www.w3.org/XML/1998/namespace";
605 public const string XMLNS = "http://www.w3.org/2000/xmlns/";
606 public const int IndexXML = 2;
607 public const int IndexXMLNS = 3;