Update sdks/wasm/framework/src/WebAssembly.Bindings/Core/Array.cs
[mono-project.git] / docs / HtmlAgilityPack / HtmlNodeNavigator.cs
blob78375ed72a10e6d0813992f51b9a7e898e6ebb56
1 // HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>
2 using System;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Text;
6 using System.Xml;
7 using System.Xml.XPath;
9 namespace HtmlAgilityPack
11 /// <summary>
12 /// Represents an HTML navigator on an HTML document seen as a data store.
13 /// </summary>
14 public class HtmlNodeNavigator : XPathNavigator
16 #region Fields
18 private int _attindex;
19 private HtmlNode _currentnode;
20 private HtmlDocument _doc = new HtmlDocument();
21 private HtmlNameTable _nametable = new HtmlNameTable();
23 internal bool Trace;
25 #endregion
27 #region Constructors
29 internal HtmlNodeNavigator()
31 Reset();
34 internal HtmlNodeNavigator(HtmlDocument doc, HtmlNode currentNode)
36 if (currentNode == null)
38 throw new ArgumentNullException("currentNode");
40 if (currentNode.OwnerDocument != doc)
42 throw new ArgumentException(HtmlDocument.HtmlExceptionRefNotChild);
44 InternalTrace(null);
46 _doc = doc;
47 Reset();
48 _currentnode = currentNode;
51 private HtmlNodeNavigator(HtmlNodeNavigator nav)
53 if (nav == null)
55 throw new ArgumentNullException("nav");
57 InternalTrace(null);
59 _doc = nav._doc;
60 _currentnode = nav._currentnode;
61 _attindex = nav._attindex;
62 _nametable = nav._nametable; // REVIEW: should we do this?
65 /// <summary>
66 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.
67 /// </summary>
68 /// <param name="stream">The input stream.</param>
69 public HtmlNodeNavigator(Stream stream)
71 _doc.Load(stream);
72 Reset();
75 /// <summary>
76 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.
77 /// </summary>
78 /// <param name="stream">The input stream.</param>
79 /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>
80 public HtmlNodeNavigator(Stream stream, bool detectEncodingFromByteOrderMarks)
82 _doc.Load(stream, detectEncodingFromByteOrderMarks);
83 Reset();
86 /// <summary>
87 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.
88 /// </summary>
89 /// <param name="stream">The input stream.</param>
90 /// <param name="encoding">The character encoding to use.</param>
91 public HtmlNodeNavigator(Stream stream, Encoding encoding)
93 _doc.Load(stream, encoding);
94 Reset();
97 /// <summary>
98 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.
99 /// </summary>
100 /// <param name="stream">The input stream.</param>
101 /// <param name="encoding">The character encoding to use.</param>
102 /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>
103 public HtmlNodeNavigator(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
105 _doc.Load(stream, encoding, detectEncodingFromByteOrderMarks);
106 Reset();
109 /// <summary>
110 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a stream.
111 /// </summary>
112 /// <param name="stream">The input stream.</param>
113 /// <param name="encoding">The character encoding to use.</param>
114 /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the stream.</param>
115 /// <param name="buffersize">The minimum buffer size.</param>
116 public HtmlNodeNavigator(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)
118 _doc.Load(stream, encoding, detectEncodingFromByteOrderMarks, buffersize);
119 Reset();
122 /// <summary>
123 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a TextReader.
124 /// </summary>
125 /// <param name="reader">The TextReader used to feed the HTML data into the document.</param>
126 public HtmlNodeNavigator(TextReader reader)
128 _doc.Load(reader);
129 Reset();
132 /// <summary>
133 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.
134 /// </summary>
135 /// <param name="path">The complete file path to be read.</param>
136 public HtmlNodeNavigator(string path)
138 _doc.Load(path);
139 Reset();
142 /// <summary>
143 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.
144 /// </summary>
145 /// <param name="path">The complete file path to be read.</param>
146 /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>
147 public HtmlNodeNavigator(string path, bool detectEncodingFromByteOrderMarks)
149 _doc.Load(path, detectEncodingFromByteOrderMarks);
150 Reset();
153 /// <summary>
154 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.
155 /// </summary>
156 /// <param name="path">The complete file path to be read.</param>
157 /// <param name="encoding">The character encoding to use.</param>
158 public HtmlNodeNavigator(string path, Encoding encoding)
160 _doc.Load(path, encoding);
161 Reset();
164 /// <summary>
165 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.
166 /// </summary>
167 /// <param name="path">The complete file path to be read.</param>
168 /// <param name="encoding">The character encoding to use.</param>
169 /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>
170 public HtmlNodeNavigator(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
172 _doc.Load(path, encoding, detectEncodingFromByteOrderMarks);
173 Reset();
176 /// <summary>
177 /// Initializes a new instance of the HtmlNavigator and loads an HTML document from a file.
178 /// </summary>
179 /// <param name="path">The complete file path to be read.</param>
180 /// <param name="encoding">The character encoding to use.</param>
181 /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>
182 /// <param name="buffersize">The minimum buffer size.</param>
183 public HtmlNodeNavigator(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)
185 _doc.Load(path, encoding, detectEncodingFromByteOrderMarks, buffersize);
186 Reset();
189 #endregion
191 #region Properties
193 /// <summary>
194 /// Gets the base URI for the current node.
195 /// Always returns string.Empty in the case of HtmlNavigator implementation.
196 /// </summary>
197 public override string BaseURI
201 InternalTrace(">");
202 return _nametable.GetOrAdd(string.Empty);
206 /// <summary>
207 /// Gets the current HTML document.
208 /// </summary>
209 public HtmlDocument CurrentDocument
211 get { return _doc; }
214 /// <summary>
215 /// Gets the current HTML node.
216 /// </summary>
217 public HtmlNode CurrentNode
219 get { return _currentnode; }
222 /// <summary>
223 /// Gets a value indicating whether the current node has child nodes.
224 /// </summary>
225 public override bool HasAttributes
229 InternalTrace(">" + (_currentnode.Attributes.Count > 0));
230 return (_currentnode.Attributes.Count > 0);
234 /// <summary>
235 /// Gets a value indicating whether the current node has child nodes.
236 /// </summary>
237 public override bool HasChildren
241 InternalTrace(">" + (_currentnode.ChildNodes.Count > 0));
242 return (_currentnode.ChildNodes.Count > 0);
246 /// <summary>
247 /// Gets a value indicating whether the current node is an empty element.
248 /// </summary>
249 public override bool IsEmptyElement
253 InternalTrace(">" + !HasChildren);
254 // REVIEW: is this ok?
255 return !HasChildren;
259 /// <summary>
260 /// Gets the name of the current HTML node without the namespace prefix.
261 /// </summary>
262 public override string LocalName
266 if (_attindex != -1)
268 InternalTrace("att>" + _currentnode.Attributes[_attindex].Name);
269 return _nametable.GetOrAdd(_currentnode.Attributes[_attindex].Name);
271 InternalTrace("node>" + _currentnode.Name);
272 return _nametable.GetOrAdd(_currentnode.Name);
276 /// <summary>
277 /// Gets the qualified name of the current node.
278 /// </summary>
279 public override string Name
283 InternalTrace(">" + _currentnode.Name);
284 return _nametable.GetOrAdd(_currentnode.Name);
288 /// <summary>
289 /// Gets the namespace URI (as defined in the W3C Namespace Specification) of the current node.
290 /// Always returns string.Empty in the case of HtmlNavigator implementation.
291 /// </summary>
292 public override string NamespaceURI
296 InternalTrace(">");
297 return _nametable.GetOrAdd(string.Empty);
301 /// <summary>
302 /// Gets the <see cref="XmlNameTable"/> associated with this implementation.
303 /// </summary>
304 public override XmlNameTable NameTable
308 InternalTrace(null);
309 return _nametable;
313 /// <summary>
314 /// Gets the type of the current node.
315 /// </summary>
316 public override XPathNodeType NodeType
320 switch (_currentnode.NodeType)
322 case HtmlNodeType.Comment:
323 InternalTrace(">" + XPathNodeType.Comment);
324 return XPathNodeType.Comment;
326 case HtmlNodeType.Document:
327 InternalTrace(">" + XPathNodeType.Root);
328 return XPathNodeType.Root;
330 case HtmlNodeType.Text:
331 InternalTrace(">" + XPathNodeType.Text);
332 return XPathNodeType.Text;
334 case HtmlNodeType.Element:
336 if (_attindex != -1)
338 InternalTrace(">" + XPathNodeType.Attribute);
339 return XPathNodeType.Attribute;
341 InternalTrace(">" + XPathNodeType.Element);
342 return XPathNodeType.Element;
345 default:
346 throw new NotImplementedException("Internal error: Unhandled HtmlNodeType: " +
347 _currentnode.NodeType);
352 /// <summary>
353 /// Gets the prefix associated with the current node.
354 /// Always returns string.Empty in the case of HtmlNavigator implementation.
355 /// </summary>
356 public override string Prefix
360 InternalTrace(null);
361 return _nametable.GetOrAdd(string.Empty);
365 /// <summary>
366 /// Gets the text value of the current node.
367 /// </summary>
368 public override string Value
372 InternalTrace("nt=" + _currentnode.NodeType);
373 switch (_currentnode.NodeType)
375 case HtmlNodeType.Comment:
376 InternalTrace(">" + ((HtmlCommentNode) _currentnode).Comment);
377 return ((HtmlCommentNode) _currentnode).Comment;
379 case HtmlNodeType.Document:
380 InternalTrace(">");
381 return "";
383 case HtmlNodeType.Text:
384 InternalTrace(">" + ((HtmlTextNode) _currentnode).Text);
385 return ((HtmlTextNode) _currentnode).Text;
387 case HtmlNodeType.Element:
389 if (_attindex != -1)
391 InternalTrace(">" + _currentnode.Attributes[_attindex].Value);
392 return _currentnode.Attributes[_attindex].Value;
394 return _currentnode.InnerText;
397 default:
398 throw new NotImplementedException("Internal error: Unhandled HtmlNodeType: " +
399 _currentnode.NodeType);
404 /// <summary>
405 /// Gets the xml:lang scope for the current node.
406 /// Always returns string.Empty in the case of HtmlNavigator implementation.
407 /// </summary>
408 public override string XmlLang
412 InternalTrace(null);
413 return _nametable.GetOrAdd(string.Empty);
417 #endregion
419 #region Public Methods
421 /// <summary>
422 /// Creates a new HtmlNavigator positioned at the same node as this HtmlNavigator.
423 /// </summary>
424 /// <returns>A new HtmlNavigator object positioned at the same node as the original HtmlNavigator.</returns>
425 public override XPathNavigator Clone()
427 InternalTrace(null);
428 return new HtmlNodeNavigator(this);
431 /// <summary>
432 /// Gets the value of the HTML attribute with the specified LocalName and NamespaceURI.
433 /// </summary>
434 /// <param name="localName">The local name of the HTML attribute.</param>
435 /// <param name="namespaceURI">The namespace URI of the attribute. Unsupported with the HtmlNavigator implementation.</param>
436 /// <returns>The value of the specified HTML attribute. String.Empty or null if a matching attribute is not found or if the navigator is not positioned on an element node.</returns>
437 public override string GetAttribute(string localName, string namespaceURI)
439 InternalTrace("localName=" + localName + ", namespaceURI=" + namespaceURI);
440 HtmlAttribute att = _currentnode.Attributes[localName];
441 if (att == null)
443 InternalTrace(">null");
444 return null;
446 InternalTrace(">" + att.Value);
447 return att.Value;
450 /// <summary>
451 /// Returns the value of the namespace node corresponding to the specified local name.
452 /// Always returns string.Empty for the HtmlNavigator implementation.
453 /// </summary>
454 /// <param name="name">The local name of the namespace node.</param>
455 /// <returns>Always returns string.Empty for the HtmlNavigator implementation.</returns>
456 public override string GetNamespace(string name)
458 InternalTrace("name=" + name);
459 return string.Empty;
462 /// <summary>
463 /// Determines whether the current HtmlNavigator is at the same position as the specified HtmlNavigator.
464 /// </summary>
465 /// <param name="other">The HtmlNavigator that you want to compare against.</param>
466 /// <returns>true if the two navigators have the same position, otherwise, false.</returns>
467 public override bool IsSamePosition(XPathNavigator other)
469 HtmlNodeNavigator nav = other as HtmlNodeNavigator;
470 if (nav == null)
472 InternalTrace(">false");
473 return false;
475 InternalTrace(">" + (nav._currentnode == _currentnode));
476 return (nav._currentnode == _currentnode);
479 /// <summary>
480 /// Moves to the same position as the specified HtmlNavigator.
481 /// </summary>
482 /// <param name="other">The HtmlNavigator positioned on the node that you want to move to.</param>
483 /// <returns>true if successful, otherwise false. If false, the position of the navigator is unchanged.</returns>
484 public override bool MoveTo(XPathNavigator other)
486 HtmlNodeNavigator nav = other as HtmlNodeNavigator;
487 if (nav == null)
489 InternalTrace(">false (nav is not an HtmlNodeNavigator)");
490 return false;
492 InternalTrace("moveto oid=" + nav.GetHashCode()
493 + ", n:" + nav._currentnode.Name
494 + ", a:" + nav._attindex);
496 if (nav._doc == _doc)
498 _currentnode = nav._currentnode;
499 _attindex = nav._attindex;
500 InternalTrace(">true");
501 return true;
503 // we don't know how to handle that
504 InternalTrace(">false (???)");
505 return false;
508 /// <summary>
509 /// Moves to the HTML attribute with matching LocalName and NamespaceURI.
510 /// </summary>
511 /// <param name="localName">The local name of the HTML attribute.</param>
512 /// <param name="namespaceURI">The namespace URI of the attribute. Unsupported with the HtmlNavigator implementation.</param>
513 /// <returns>true if the HTML attribute is found, otherwise, false. If false, the position of the navigator does not change.</returns>
514 public override bool MoveToAttribute(string localName, string namespaceURI)
516 InternalTrace("localName=" + localName + ", namespaceURI=" + namespaceURI);
517 int index = _currentnode.Attributes.GetAttributeIndex(localName);
518 if (index == -1)
520 InternalTrace(">false");
521 return false;
523 _attindex = index;
524 InternalTrace(">true");
525 return true;
528 /// <summary>
529 /// Moves to the first sibling of the current node.
530 /// </summary>
531 /// <returns>true if the navigator is successful moving to the first sibling node, false if there is no first sibling or if the navigator is currently positioned on an attribute node.</returns>
532 public override bool MoveToFirst()
534 if (_currentnode.ParentNode == null)
536 InternalTrace(">false");
537 return false;
539 if (_currentnode.ParentNode.FirstChild == null)
541 InternalTrace(">false");
542 return false;
544 _currentnode = _currentnode.ParentNode.FirstChild;
545 InternalTrace(">true");
546 return true;
549 /// <summary>
550 /// Moves to the first HTML attribute.
551 /// </summary>
552 /// <returns>true if the navigator is successful moving to the first HTML attribute, otherwise, false.</returns>
553 public override bool MoveToFirstAttribute()
555 if (!HasAttributes)
557 InternalTrace(">false");
558 return false;
560 _attindex = 0;
561 InternalTrace(">true");
562 return true;
565 /// <summary>
566 /// Moves to the first child of the current node.
567 /// </summary>
568 /// <returns>true if there is a first child node, otherwise false.</returns>
569 public override bool MoveToFirstChild()
571 if (!_currentnode.HasChildNodes)
573 InternalTrace(">false");
574 return false;
576 _currentnode = _currentnode.ChildNodes[0];
577 InternalTrace(">true");
578 return true;
581 /// <summary>
582 /// Moves the XPathNavigator to the first namespace node of the current element.
583 /// Always returns false for the HtmlNavigator implementation.
584 /// </summary>
585 /// <param name="scope">An XPathNamespaceScope value describing the namespace scope.</param>
586 /// <returns>Always returns false for the HtmlNavigator implementation.</returns>
587 public override bool MoveToFirstNamespace(XPathNamespaceScope scope)
589 InternalTrace(null);
590 return false;
593 /// <summary>
594 /// Moves to the node that has an attribute of type ID whose value matches the specified string.
595 /// </summary>
596 /// <param name="id">A string representing the ID value of the node to which you want to move. This argument does not need to be atomized.</param>
597 /// <returns>true if the move was successful, otherwise false. If false, the position of the navigator is unchanged.</returns>
598 public override bool MoveToId(string id)
600 InternalTrace("id=" + id);
601 HtmlNode node = _doc.GetElementbyId(id);
602 if (node == null)
604 InternalTrace(">false");
605 return false;
607 _currentnode = node;
608 InternalTrace(">true");
609 return true;
612 /// <summary>
613 /// Moves the XPathNavigator to the namespace node with the specified local name.
614 /// Always returns false for the HtmlNavigator implementation.
615 /// </summary>
616 /// <param name="name">The local name of the namespace node.</param>
617 /// <returns>Always returns false for the HtmlNavigator implementation.</returns>
618 public override bool MoveToNamespace(string name)
620 InternalTrace("name=" + name);
621 return false;
624 /// <summary>
625 /// Moves to the next sibling of the current node.
626 /// </summary>
627 /// <returns>true if the navigator is successful moving to the next sibling node, false if there are no more siblings or if the navigator is currently positioned on an attribute node. If false, the position of the navigator is unchanged.</returns>
628 public override bool MoveToNext()
630 if (_currentnode.NextSibling == null)
632 InternalTrace(">false");
633 return false;
635 InternalTrace("_c=" + _currentnode.CloneNode(false).OuterHtml);
636 InternalTrace("_n=" + _currentnode.NextSibling.CloneNode(false).OuterHtml);
637 _currentnode = _currentnode.NextSibling;
638 InternalTrace(">true");
639 return true;
642 /// <summary>
643 /// Moves to the next HTML attribute.
644 /// </summary>
645 /// <returns></returns>
646 public override bool MoveToNextAttribute()
648 InternalTrace(null);
649 if (_attindex >= (_currentnode.Attributes.Count - 1))
651 InternalTrace(">false");
652 return false;
654 _attindex++;
655 InternalTrace(">true");
656 return true;
659 /// <summary>
660 /// Moves the XPathNavigator to the next namespace node.
661 /// Always returns falsefor the HtmlNavigator implementation.
662 /// </summary>
663 /// <param name="scope">An XPathNamespaceScope value describing the namespace scope.</param>
664 /// <returns>Always returns false for the HtmlNavigator implementation.</returns>
665 public override bool MoveToNextNamespace(XPathNamespaceScope scope)
667 InternalTrace(null);
668 return false;
671 /// <summary>
672 /// Moves to the parent of the current node.
673 /// </summary>
674 /// <returns>true if there is a parent node, otherwise false.</returns>
675 public override bool MoveToParent()
677 if (_currentnode.ParentNode == null)
679 InternalTrace(">false");
680 return false;
682 _currentnode = _currentnode.ParentNode;
683 InternalTrace(">true");
684 return true;
687 /// <summary>
688 /// Moves to the previous sibling of the current node.
689 /// </summary>
690 /// <returns>true if the navigator is successful moving to the previous sibling node, false if there is no previous sibling or if the navigator is currently positioned on an attribute node.</returns>
691 public override bool MoveToPrevious()
693 if (_currentnode.PreviousSibling == null)
695 InternalTrace(">false");
696 return false;
698 _currentnode = _currentnode.PreviousSibling;
699 InternalTrace(">true");
700 return true;
703 /// <summary>
704 /// Moves to the root node to which the current node belongs.
705 /// </summary>
706 public override void MoveToRoot()
708 _currentnode = _doc.DocumentNode;
709 InternalTrace(null);
712 #endregion
714 #region Internal Methods
716 [Conditional("TRACE")]
717 internal void InternalTrace(object traceValue)
719 if (!Trace)
721 return;
723 StackFrame sf = new StackFrame(1, true);
724 string name = sf.GetMethod().Name;
725 string nodename = _currentnode == null ? "(null)" : _currentnode.Name;
726 string nodevalue;
727 if (_currentnode == null)
729 nodevalue = "(null)";
731 else
733 switch (_currentnode.NodeType)
735 case HtmlNodeType.Comment:
736 nodevalue = ((HtmlCommentNode) _currentnode).Comment;
737 break;
739 case HtmlNodeType.Document:
740 nodevalue = "";
741 break;
743 case HtmlNodeType.Text:
744 nodevalue = ((HtmlTextNode) _currentnode).Text;
745 break;
747 default:
748 nodevalue = _currentnode.CloneNode(false).OuterHtml;
749 break;
752 System.Diagnostics.Trace.WriteLine(string.Format("oid={0},n={1},a={2},v={3},{4}", GetHashCode(), nodename, _attindex, nodevalue, traceValue), "N!" + name);
755 #endregion
757 #region Private Methods
759 private void Reset()
761 InternalTrace(null);
762 _currentnode = _doc.DocumentNode;
763 _attindex = -1;
766 #endregion