1 // HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>
\r
3 using System.Collections;
\r
4 using System.Collections.Generic;
\r
6 namespace HtmlAgilityPack
\r
9 /// Represents a combined list and collection of HTML nodes.
\r
11 public class HtmlNodeCollection : IList<HtmlNode>
\r
15 private readonly HtmlNode _parentnode;
\r
16 private readonly List<HtmlNode> _items = new List<HtmlNode>();
\r
20 #region Constructors
\r
23 /// Initialize the HtmlNodeCollection with the base parent node
\r
25 /// <param name="parentnode">The base node of the collection</param>
\r
26 public HtmlNodeCollection(HtmlNode parentnode)
\r
28 _parentnode = parentnode; // may be null
\r
36 /// Gets a given node from the list.
\r
38 public int this[HtmlNode node]
\r
42 int index = GetNodeIndex(node);
\r
45 throw new ArgumentOutOfRangeException("node",
\r
46 "Node \"" + node.CloneNode(false).OuterHtml +
\r
47 "\" was not found in the collection");
\r
54 /// Get node with tag name
\r
56 /// <param name="nodeName"></param>
\r
57 /// <returns></returns>
\r
58 public HtmlNode this[string nodeName]
\r
62 nodeName = nodeName.ToLower();
\r
63 for (int i = 0; i < _items.Count; i++)
\r
64 if (_items[i].Equals(nodeName))
\r
73 #region IList<HtmlNode> Members
\r
76 /// Gets the number of elements actually contained in the list.
\r
80 get { return _items.Count; }
\r
84 /// Is collection read only
\r
86 public bool IsReadOnly
\r
88 get { return false; }
\r
92 /// Gets the node at the specified index.
\r
94 public HtmlNode this[int index]
\r
96 get { return _items[index]; }
\r
97 set { _items[index] = value; }
\r
101 /// Add node to the collection
\r
103 /// <param name="node"></param>
\r
104 public void Add(HtmlNode node)
\r
110 /// Clears out the collection of HtmlNodes. Removes each nodes reference to parentnode, nextnode and prevnode
\r
112 public void Clear()
\r
114 foreach (HtmlNode node in _items)
\r
116 node.ParentNode = null;
\r
117 node.NextSibling = null;
\r
118 node.PreviousSibling = null;
\r
124 /// Gets existence of node in collection
\r
126 /// <param name="item"></param>
\r
127 /// <returns></returns>
\r
128 public bool Contains(HtmlNode item)
\r
130 return _items.Contains(item);
\r
134 /// Copy collection to array
\r
136 /// <param name="array"></param>
\r
137 /// <param name="arrayIndex"></param>
\r
138 public void CopyTo(HtmlNode[] array, int arrayIndex)
\r
140 _items.CopyTo(array, arrayIndex);
\r
146 /// <returns></returns>
\r
147 IEnumerator<HtmlNode> IEnumerable<HtmlNode>.GetEnumerator()
\r
149 return _items.GetEnumerator();
\r
153 /// Get Explicit Enumerator
\r
155 /// <returns></returns>
\r
156 IEnumerator IEnumerable.GetEnumerator()
\r
158 return _items.GetEnumerator();
\r
162 /// Get index of node
\r
164 /// <param name="item"></param>
\r
165 /// <returns></returns>
\r
166 public int IndexOf(HtmlNode item)
\r
168 return _items.IndexOf(item);
\r
172 /// Insert node at index
\r
174 /// <param name="index"></param>
\r
175 /// <param name="node"></param>
\r
176 public void Insert(int index, HtmlNode node)
\r
178 HtmlNode next = null;
\r
179 HtmlNode prev = null;
\r
183 prev = _items[index - 1];
\r
186 if (index < _items.Count)
\r
188 next = _items[index];
\r
191 _items.Insert(index, node);
\r
197 throw new InvalidProgramException("Unexpected error.");
\r
199 prev._nextnode = node;
\r
204 next._prevnode = node;
\r
207 node._prevnode = prev;
\r
210 throw new InvalidProgramException("Unexpected error.");
\r
212 node._nextnode = next;
\r
213 node._parentnode = _parentnode;
\r
219 /// <param name="item"></param>
\r
220 /// <returns></returns>
\r
221 public bool Remove(HtmlNode item)
\r
223 int i = _items.IndexOf(item);
\r
229 /// Remove <see cref="HtmlNode"/> at index
\r
231 /// <param name="index"></param>
\r
232 public void RemoveAt(int index)
\r
234 HtmlNode next = null;
\r
235 HtmlNode prev = null;
\r
236 HtmlNode oldnode = _items[index];
\r
240 prev = _items[index - 1];
\r
243 if (index < (_items.Count - 1))
\r
245 next = _items[index + 1];
\r
248 _items.RemoveAt(index);
\r
254 throw new InvalidProgramException("Unexpected error.");
\r
256 prev._nextnode = next;
\r
261 next._prevnode = prev;
\r
264 oldnode._prevnode = null;
\r
265 oldnode._nextnode = null;
\r
266 oldnode._parentnode = null;
\r
271 #region Public Methods
\r
274 /// Get first instance of node in supplied collection
\r
276 /// <param name="items"></param>
\r
277 /// <param name="name"></param>
\r
278 /// <returns></returns>
\r
279 public static HtmlNode FindFirst(HtmlNodeCollection items, string name)
\r
281 foreach (HtmlNode node in items)
\r
283 if (node.Name.ToLower().Contains(name))
\r
285 if (node.HasChildNodes)
\r
287 HtmlNode returnNode = FindFirst(node.ChildNodes, name);
\r
288 if (returnNode != null)
\r
296 /// Add node to the end of the collection
\r
298 /// <param name="node"></param>
\r
299 public void Append(HtmlNode node)
\r
301 HtmlNode last = null;
\r
302 if (_items.Count > 0)
\r
304 last = _items[_items.Count - 1];
\r
308 node._prevnode = last;
\r
309 node._nextnode = null;
\r
310 node._parentnode = _parentnode;
\r
315 throw new InvalidProgramException("Unexpected error.");
\r
317 last._nextnode = node;
\r
322 /// Get first instance of node with name
\r
324 /// <param name="name"></param>
\r
325 /// <returns></returns>
\r
326 public HtmlNode FindFirst(string name)
\r
328 return FindFirst(this, name);
\r
332 /// Get index of node
\r
334 /// <param name="node"></param>
\r
335 /// <returns></returns>
\r
336 public int GetNodeIndex(HtmlNode node)
\r
338 // TODO: should we rewrite this? what would be the key of a node?
\r
339 for (int i = 0; i < _items.Count; i++)
\r
341 if (node == (_items[i]))
\r
350 /// Add node to the beginning of the collection
\r
352 /// <param name="node"></param>
\r
353 public void Prepend(HtmlNode node)
\r
355 HtmlNode first = null;
\r
356 if (_items.Count > 0)
\r
361 _items.Insert(0, node);
\r
365 throw new InvalidProgramException("Unexpected error.");
\r
367 node._nextnode = first;
\r
368 node._prevnode = null;
\r
369 node._parentnode = _parentnode;
\r
372 first._prevnode = node;
\r
377 /// Remove node at index
\r
379 /// <param name="index"></param>
\r
380 /// <returns></returns>
\r
381 public bool Remove(int index)
\r
388 /// Replace node at index
\r
390 /// <param name="index"></param>
\r
391 /// <param name="node"></param>
\r
392 public void Replace(int index, HtmlNode node)
\r
394 HtmlNode next = null;
\r
395 HtmlNode prev = null;
\r
396 HtmlNode oldnode = _items[index];
\r
400 prev = _items[index - 1];
\r
403 if (index < (_items.Count - 1))
\r
405 next = _items[index + 1];
\r
408 _items[index] = node;
\r
414 throw new InvalidProgramException("Unexpected error.");
\r
416 prev._nextnode = node;
\r
421 next._prevnode = node;
\r
424 node._prevnode = prev;
\r
428 throw new InvalidProgramException("Unexpected error.");
\r
431 node._nextnode = next;
\r
432 node._parentnode = _parentnode;
\r
434 oldnode._prevnode = null;
\r
435 oldnode._nextnode = null;
\r
436 oldnode._parentnode = null;
\r
441 #region LINQ Methods
\r
444 /// Get all node descended from this collection
\r
446 /// <returns></returns>
\r
447 public IEnumerable<HtmlNode> DescendantNodes()
\r
449 foreach (HtmlNode item in _items)
\r
450 foreach (HtmlNode n in item.DescendantNodes())
\r
455 /// Get all node descended from this collection
\r
457 /// <returns></returns>
\r
458 public IEnumerable<HtmlNode> Descendants()
\r
460 foreach (HtmlNode item in _items)
\r
461 foreach (HtmlNode n in item.Descendants())
\r
466 /// Get all node descended from this collection with matching name
\r
468 /// <returns></returns>
\r
469 public IEnumerable<HtmlNode> Descendants(string name)
\r
471 foreach (HtmlNode item in _items)
\r
472 foreach (HtmlNode n in item.Descendants(name))
\r
477 /// Gets all first generation elements in collection
\r
479 /// <returns></returns>
\r
480 public IEnumerable<HtmlNode> Elements()
\r
482 foreach (HtmlNode item in _items)
\r
483 foreach (HtmlNode n in item.ChildNodes)
\r
488 /// Gets all first generation elements matching name
\r
490 /// <param name="name"></param>
\r
491 /// <returns></returns>
\r
492 public IEnumerable<HtmlNode> Elements(string name)
\r
494 foreach (HtmlNode item in _items)
\r
495 foreach (HtmlNode n in item.Elements(name))
\r
500 /// All first generation nodes in collection
\r
502 /// <returns></returns>
\r
503 public IEnumerable<HtmlNode> Nodes()
\r
505 foreach (HtmlNode item in _items)
\r
506 foreach (HtmlNode n in item.ChildNodes)
\r