Fix LinearGradientMode parameter validation to match corefx (#5672)
[mono.git] / docs / HtmlAgilityPack / HtmlNodeCollection.cs
1 // HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
2 using System;\r
3 using System.Collections;\r
4 using System.Collections.Generic;\r
5 \r
6 namespace HtmlAgilityPack\r
7 {\r
8     /// <summary>\r
9     /// Represents a combined list and collection of HTML nodes.\r
10     /// </summary>\r
11     public class HtmlNodeCollection : IList<HtmlNode>\r
12     {\r
13         #region Fields\r
14 \r
15         private readonly HtmlNode _parentnode;\r
16         private readonly List<HtmlNode> _items = new List<HtmlNode>();\r
17 \r
18         #endregion\r
19 \r
20         #region Constructors\r
21 \r
22         /// <summary>\r
23         /// Initialize the HtmlNodeCollection with the base parent node\r
24         /// </summary>\r
25         /// <param name="parentnode">The base node of the collection</param>\r
26         public HtmlNodeCollection(HtmlNode parentnode)\r
27         {\r
28             _parentnode = parentnode; // may be null\r
29         }\r
30 \r
31         #endregion\r
32 \r
33         #region Properties\r
34 \r
35         /// <summary>\r
36         /// Gets a given node from the list.\r
37         /// </summary>\r
38         public int this[HtmlNode node]\r
39         {\r
40             get\r
41             {\r
42                 int index = GetNodeIndex(node);\r
43                 if (index == -1)\r
44                 {\r
45                     throw new ArgumentOutOfRangeException("node",\r
46                                                           "Node \"" + node.CloneNode(false).OuterHtml +\r
47                                                           "\" was not found in the collection");\r
48                 }\r
49                 return index;\r
50             }\r
51         }\r
52 \r
53         /// <summary>\r
54         /// Get node with tag name\r
55         /// </summary>\r
56         /// <param name="nodeName"></param>\r
57         /// <returns></returns>\r
58         public HtmlNode this[string nodeName]\r
59         {\r
60             get\r
61             {\r
62                 nodeName = nodeName.ToLower();\r
63                 for (int i = 0; i < _items.Count; i++)\r
64                     if (_items[i].Equals(nodeName))\r
65                         return _items[i];\r
66 \r
67                 return null;\r
68             }\r
69         }\r
70 \r
71         #endregion\r
72 \r
73         #region IList<HtmlNode> Members\r
74 \r
75         /// <summary>\r
76         /// Gets the number of elements actually contained in the list.\r
77         /// </summary>\r
78         public int Count\r
79         {\r
80             get { return _items.Count; }\r
81         }\r
82 \r
83         /// <summary>\r
84         /// Is collection read only\r
85         /// </summary>\r
86         public bool IsReadOnly\r
87         {\r
88             get { return false; }\r
89         }\r
90 \r
91         /// <summary>\r
92         /// Gets the node at the specified index.\r
93         /// </summary>\r
94         public HtmlNode this[int index]\r
95         {\r
96             get { return _items[index]; }\r
97             set { _items[index] = value; }\r
98         }\r
99 \r
100         /// <summary>\r
101         /// Add node to the collection\r
102         /// </summary>\r
103         /// <param name="node"></param>\r
104         public void Add(HtmlNode node)\r
105         {\r
106             _items.Add(node);\r
107         }\r
108 \r
109         /// <summary>\r
110         /// Clears out the collection of HtmlNodes. Removes each nodes reference to parentnode, nextnode and prevnode\r
111         /// </summary>\r
112         public void Clear()\r
113         {\r
114             foreach (HtmlNode node in _items)\r
115             {\r
116                 node.ParentNode = null;\r
117                 node.NextSibling = null;\r
118                 node.PreviousSibling = null;\r
119             }\r
120             _items.Clear();\r
121         }\r
122 \r
123         /// <summary>\r
124         /// Gets existence of node in collection\r
125         /// </summary>\r
126         /// <param name="item"></param>\r
127         /// <returns></returns>\r
128         public bool Contains(HtmlNode item)\r
129         {\r
130             return _items.Contains(item);\r
131         }\r
132 \r
133         /// <summary>\r
134         /// Copy collection to array\r
135         /// </summary>\r
136         /// <param name="array"></param>\r
137         /// <param name="arrayIndex"></param>\r
138         public void CopyTo(HtmlNode[] array, int arrayIndex)\r
139         {\r
140             _items.CopyTo(array, arrayIndex);\r
141         }\r
142 \r
143         /// <summary>\r
144         /// Get Enumerator\r
145         /// </summary>\r
146         /// <returns></returns>\r
147         IEnumerator<HtmlNode> IEnumerable<HtmlNode>.GetEnumerator()\r
148         {\r
149             return _items.GetEnumerator();\r
150         }\r
151 \r
152         /// <summary>\r
153         /// Get Explicit Enumerator\r
154         /// </summary>\r
155         /// <returns></returns>\r
156         IEnumerator IEnumerable.GetEnumerator()\r
157         {\r
158             return _items.GetEnumerator();\r
159         }\r
160 \r
161         /// <summary>\r
162         /// Get index of node\r
163         /// </summary>\r
164         /// <param name="item"></param>\r
165         /// <returns></returns>\r
166         public int IndexOf(HtmlNode item)\r
167         {\r
168             return _items.IndexOf(item);\r
169         }\r
170 \r
171         /// <summary>\r
172         /// Insert node at index\r
173         /// </summary>\r
174         /// <param name="index"></param>\r
175         /// <param name="node"></param>\r
176         public void Insert(int index, HtmlNode node)\r
177         {\r
178             HtmlNode next = null;\r
179             HtmlNode prev = null;\r
180 \r
181             if (index > 0)\r
182             {\r
183                 prev = _items[index - 1];\r
184             }\r
185 \r
186             if (index < _items.Count)\r
187             {\r
188                 next = _items[index];\r
189             }\r
190 \r
191             _items.Insert(index, node);\r
192 \r
193             if (prev != null)\r
194             {\r
195                 if (node == prev)\r
196                 {\r
197                     throw new InvalidProgramException("Unexpected error.");\r
198                 }\r
199                 prev._nextnode = node;\r
200             }\r
201 \r
202             if (next != null)\r
203             {\r
204                 next._prevnode = node;\r
205             }\r
206 \r
207             node._prevnode = prev;\r
208             if (next == node)\r
209             {\r
210                 throw new InvalidProgramException("Unexpected error.");\r
211             }\r
212             node._nextnode = next;\r
213             node._parentnode = _parentnode;\r
214         }\r
215 \r
216         /// <summary>\r
217         /// Remove node\r
218         /// </summary>\r
219         /// <param name="item"></param>\r
220         /// <returns></returns>\r
221         public bool Remove(HtmlNode item)\r
222         {\r
223             int i = _items.IndexOf(item);\r
224             RemoveAt(i);\r
225             return true;\r
226         }\r
227 \r
228         /// <summary>\r
229         /// Remove <see cref="HtmlNode"/> at index\r
230         /// </summary>\r
231         /// <param name="index"></param>\r
232         public void RemoveAt(int index)\r
233         {\r
234             HtmlNode next = null;\r
235             HtmlNode prev = null;\r
236             HtmlNode oldnode = _items[index];\r
237 \r
238             if (index > 0)\r
239             {\r
240                 prev = _items[index - 1];\r
241             }\r
242 \r
243             if (index < (_items.Count - 1))\r
244             {\r
245                 next = _items[index + 1];\r
246             }\r
247 \r
248             _items.RemoveAt(index);\r
249 \r
250             if (prev != null)\r
251             {\r
252                 if (next == prev)\r
253                 {\r
254                     throw new InvalidProgramException("Unexpected error.");\r
255                 }\r
256                 prev._nextnode = next;\r
257             }\r
258 \r
259             if (next != null)\r
260             {\r
261                 next._prevnode = prev;\r
262             }\r
263 \r
264             oldnode._prevnode = null;\r
265             oldnode._nextnode = null;\r
266             oldnode._parentnode = null;\r
267         }\r
268 \r
269         #endregion\r
270 \r
271         #region Public Methods\r
272 \r
273         /// <summary>\r
274         /// Get first instance of node in supplied collection\r
275         /// </summary>\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
280         {\r
281             foreach (HtmlNode node in items)\r
282             {\r
283                 if (node.Name.ToLower().Contains(name))\r
284                     return node;\r
285                 if (node.HasChildNodes)\r
286                 {\r
287                     HtmlNode returnNode = FindFirst(node.ChildNodes, name);\r
288                     if (returnNode != null)\r
289                         return returnNode;\r
290                 }\r
291             }\r
292             return null;\r
293         }\r
294 \r
295         /// <summary>\r
296         /// Add node to the end of the collection\r
297         /// </summary>\r
298         /// <param name="node"></param>\r
299         public void Append(HtmlNode node)\r
300         {\r
301             HtmlNode last = null;\r
302             if (_items.Count > 0)\r
303             {\r
304                 last = _items[_items.Count - 1];\r
305             }\r
306 \r
307             _items.Add(node);\r
308             node._prevnode = last;\r
309             node._nextnode = null;\r
310             node._parentnode = _parentnode;\r
311             if (last != null)\r
312             {\r
313                 if (last == node)\r
314                 {\r
315                     throw new InvalidProgramException("Unexpected error.");\r
316                 }\r
317                 last._nextnode = node;\r
318             }\r
319         }\r
320 \r
321         /// <summary>\r
322         /// Get first instance of node with name\r
323         /// </summary>\r
324         /// <param name="name"></param>\r
325         /// <returns></returns>\r
326         public HtmlNode FindFirst(string name)\r
327         {\r
328             return FindFirst(this, name);\r
329         }\r
330 \r
331         /// <summary>\r
332         /// Get index of node\r
333         /// </summary>\r
334         /// <param name="node"></param>\r
335         /// <returns></returns>\r
336         public int GetNodeIndex(HtmlNode node)\r
337         {\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
340             {\r
341                 if (node == (_items[i]))\r
342                 {\r
343                     return i;\r
344                 }\r
345             }\r
346             return -1;\r
347         }\r
348 \r
349         /// <summary>\r
350         /// Add node to the beginning of the collection\r
351         /// </summary>\r
352         /// <param name="node"></param>\r
353         public void Prepend(HtmlNode node)\r
354         {\r
355             HtmlNode first = null;\r
356             if (_items.Count > 0)\r
357             {\r
358                 first = _items[0];\r
359             }\r
360 \r
361             _items.Insert(0, node);\r
362 \r
363             if (node == first)\r
364             {\r
365                 throw new InvalidProgramException("Unexpected error.");\r
366             }\r
367             node._nextnode = first;\r
368             node._prevnode = null;\r
369             node._parentnode = _parentnode;\r
370             if (first != null)\r
371             {\r
372                 first._prevnode = node;\r
373             }\r
374         }\r
375 \r
376         /// <summary>\r
377         /// Remove node at index\r
378         /// </summary>\r
379         /// <param name="index"></param>\r
380         /// <returns></returns>\r
381         public bool Remove(int index)\r
382         {\r
383             RemoveAt(index);\r
384             return true;\r
385         }\r
386 \r
387         /// <summary>\r
388         /// Replace node at index\r
389         /// </summary>\r
390         /// <param name="index"></param>\r
391         /// <param name="node"></param>\r
392         public void Replace(int index, HtmlNode node)\r
393         {\r
394             HtmlNode next = null;\r
395             HtmlNode prev = null;\r
396             HtmlNode oldnode = _items[index];\r
397 \r
398             if (index > 0)\r
399             {\r
400                 prev = _items[index - 1];\r
401             }\r
402 \r
403             if (index < (_items.Count - 1))\r
404             {\r
405                 next = _items[index + 1];\r
406             }\r
407 \r
408             _items[index] = node;\r
409 \r
410             if (prev != null)\r
411             {\r
412                 if (node == prev)\r
413                 {\r
414                     throw new InvalidProgramException("Unexpected error.");\r
415                 }\r
416                 prev._nextnode = node;\r
417             }\r
418 \r
419             if (next != null)\r
420             {\r
421                 next._prevnode = node;\r
422             }\r
423 \r
424             node._prevnode = prev;\r
425 \r
426             if (next == node)\r
427             {\r
428                 throw new InvalidProgramException("Unexpected error.");\r
429             }\r
430 \r
431             node._nextnode = next;\r
432             node._parentnode = _parentnode;\r
433 \r
434             oldnode._prevnode = null;\r
435             oldnode._nextnode = null;\r
436             oldnode._parentnode = null;\r
437         }\r
438 \r
439         #endregion\r
440 \r
441         #region LINQ Methods\r
442 \r
443         /// <summary>\r
444         /// Get all node descended from this collection\r
445         /// </summary>\r
446         /// <returns></returns>\r
447         public IEnumerable<HtmlNode> DescendantNodes()\r
448         {\r
449             foreach (HtmlNode item in _items)\r
450                 foreach (HtmlNode n in item.DescendantNodes())\r
451                     yield return n;\r
452         }\r
453 \r
454         /// <summary>\r
455         /// Get all node descended from this collection\r
456         /// </summary>\r
457         /// <returns></returns>\r
458         public IEnumerable<HtmlNode> Descendants()\r
459         {\r
460             foreach (HtmlNode item in _items)\r
461                 foreach (HtmlNode n in item.Descendants())\r
462                     yield return n;\r
463         }\r
464 \r
465         /// <summary>\r
466         /// Get all node descended from this collection with matching name\r
467         /// </summary>\r
468         /// <returns></returns>\r
469         public IEnumerable<HtmlNode> Descendants(string name)\r
470         {\r
471             foreach (HtmlNode item in _items)\r
472                 foreach (HtmlNode n in item.Descendants(name))\r
473                     yield return n;\r
474         }\r
475 \r
476         /// <summary>\r
477         /// Gets all first generation elements in collection\r
478         /// </summary>\r
479         /// <returns></returns>\r
480         public IEnumerable<HtmlNode> Elements()\r
481         {\r
482             foreach (HtmlNode item in _items)\r
483                 foreach (HtmlNode n in item.ChildNodes)\r
484                     yield return n;\r
485         }\r
486 \r
487         /// <summary>\r
488         /// Gets all first generation elements matching name\r
489         /// </summary>\r
490         /// <param name="name"></param>\r
491         /// <returns></returns>\r
492         public IEnumerable<HtmlNode> Elements(string name)\r
493         {\r
494             foreach (HtmlNode item in _items)\r
495                 foreach (HtmlNode n in item.Elements(name))\r
496                     yield return n;\r
497         }\r
498 \r
499         /// <summary>\r
500         /// All first generation nodes in collection\r
501         /// </summary>\r
502         /// <returns></returns>\r
503         public IEnumerable<HtmlNode> Nodes()\r
504         {\r
505             foreach (HtmlNode item in _items)\r
506                 foreach (HtmlNode n in item.ChildNodes)\r
507                     yield return n;\r
508         }\r
509 \r
510         #endregion\r
511     }\r
512 }