Dont throw EncodingFoundException unless asked to. Should remove the occassional...
[beagle.git] / Filters / HtmlAgilityPack / HtmlAttribute.cs
blob03245026137403a2de626e3eb015c55f3b70a73f
1 /*
2 Copyright (C) 2003 Simon Mourier <simonm@microsoft.com>
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 using System;
29 using System.Collections;
31 namespace HtmlAgilityPack
33 /// <summary>
34 /// Represents an HTML attribute.
35 /// </summary>
36 public class HtmlAttribute: IComparable
38 internal int _line = 0;
39 internal int _lineposition = 0;
40 internal int _streamposition = 0;
41 internal int _namestartindex = 0;
42 internal int _namelength = 0;
43 internal int _valuestartindex = 0;
44 internal int _valuelength = 0;
45 internal HtmlDocument _ownerdocument; // attribute can exists without a node
46 internal HtmlNode _ownernode;
47 internal string _name;
48 internal string _value;
50 internal HtmlAttribute(HtmlDocument ownerdocument)
52 _ownerdocument = ownerdocument;
55 /// <summary>
56 /// Creates a duplicate of this attribute.
57 /// </summary>
58 /// <returns>The cloned attribute.</returns>
59 public HtmlAttribute Clone()
61 HtmlAttribute att = new HtmlAttribute(_ownerdocument);
62 att.Name = Name;
63 att.Value = Value;
64 return att;
67 /// <summary>
68 /// Compares the current instance with another attribute. Comparison is based on attributes' name.
69 /// </summary>
70 /// <param name="obj">An attribute to compare with this instance.</param>
71 /// <returns>A 32-bit signed integer that indicates the relative order of the names comparison.</returns>
72 public int CompareTo(object obj)
74 HtmlAttribute att = obj as HtmlAttribute;
75 if (att == null)
77 throw new ArgumentException("obj");
79 return Name.CompareTo(att.Name);
82 internal string XmlName
84 get
86 return GetXmlName(Name);
90 /// <summary>
91 /// Gets a valid XML name.
92 /// </summary>
93 /// <param name="name">Any text.</param>
94 /// <returns>A string that is a valid XML name.</returns>
95 internal static string GetXmlName(string name)
97 string xmlname = string.Empty;
98 bool nameisok = true;
99 for(int i=0;i<name.Length;i++)
101 // names are lcase
102 // note: we are very limited here
103 if (((name[i]>='a') && (name[i]<='z')) ||
104 ((name[i]>='0') && (name[i]<='9')) ||
105 // (name[i]==':') || (name[i]=='_') || (name[i]=='-') || (name[i]=='.')) // these are bads in fact
106 (name[i]=='_') || (name[i]=='-') || (name[i]=='.'))
108 xmlname += name[i];
110 else
112 nameisok = false;
113 byte[] bytes = System.Text.Encoding.UTF8.GetBytes(new char[]{name[i]});
114 for(int j=0;j<bytes.Length;j++)
116 xmlname += bytes[j].ToString("x2");
118 xmlname += "_";
122 if (nameisok)
124 return xmlname;
126 return "_" + xmlname;
129 internal string XmlValue
133 return Value;
137 /// <summary>
138 /// Gets the qualified name of the attribute.
139 /// </summary>
140 public string Name
144 if (_name == null)
146 _name = _ownerdocument._text.Substring(_namestartindex, _namelength).ToLower();
148 return _name;
152 if (value == null)
154 throw new ArgumentNullException("value");
156 _name = value.ToLower();
157 if (_ownernode != null)
159 _ownernode._innerchanged = true;
160 _ownernode._outerchanged = true;
165 /// <summary>
166 /// Gets or sets the value of the attribute.
167 /// </summary>
168 public string Value
172 if (_value == null)
174 _value = _ownerdocument._text.Substring(_valuestartindex, _valuelength);
176 return _value;
180 _value = value;
181 if (_ownernode != null)
183 _ownernode._innerchanged = true;
184 _ownernode._outerchanged = true;
189 /// <summary>
190 /// Gets the line number of this attribute in the document.
191 /// </summary>
192 public int Line
196 return _line;
200 /// <summary>
201 /// Gets the column number of this attribute in the document.
202 /// </summary>
203 public int LinePosition
207 return _lineposition;
211 /// <summary>
212 /// Gets the stream position of this attribute in the document, relative to the start of the document.
213 /// </summary>
214 public int StreamPosition
218 return _streamposition;
222 /// <summary>
223 /// Gets the HTML node to which this attribute belongs.
224 /// </summary>
225 public HtmlNode OwnerNode
229 return _ownernode;
233 /// <summary>
234 /// Gets the HTML document to which this attribute belongs.
235 /// </summary>
236 public HtmlDocument OwnerDocument
240 return _ownerdocument;
246 /// <summary>
247 /// Represents a combined list and collection of HTML nodes.
248 /// </summary>
249 public class HtmlAttributeCollection: IEnumerable
251 internal Hashtable _hashitems = new Hashtable();
252 private ArrayList _items = new ArrayList();
253 private HtmlNode _ownernode;
255 internal HtmlAttributeCollection(HtmlNode ownernode)
257 _ownernode = ownernode;
260 /// <summary>
261 /// Inserts the specified attribute as the last attribute in the collection.
262 /// </summary>
263 /// <param name="newAttribute">The attribute to insert. May not be null.</param>
264 /// <returns>The appended attribute.</returns>
265 public HtmlAttribute Append(HtmlAttribute newAttribute)
267 if (newAttribute == null)
269 throw new ArgumentNullException("newAttribute");
272 _hashitems[newAttribute.Name] = newAttribute;
273 newAttribute._ownernode = _ownernode;
274 _items.Add(newAttribute);
276 _ownernode._innerchanged = true;
277 _ownernode._outerchanged = true;
278 return newAttribute;
281 /// <summary>
282 /// Creates and inserts a new attribute as the last attribute in the collection.
283 /// </summary>
284 /// <param name="name">The name of the attribute to insert.</param>
285 /// <returns>The appended attribute.</returns>
286 public HtmlAttribute Append(string name)
288 HtmlAttribute att = _ownernode._ownerdocument.CreateAttribute(name);
289 return Append(att);
292 /// <summary>
293 /// Creates and inserts a new attribute as the last attribute in the collection.
294 /// </summary>
295 /// <param name="name">The name of the attribute to insert.</param>
296 /// <param name="value">The value of the attribute to insert.</param>
297 /// <returns>The appended attribute.</returns>
298 public HtmlAttribute Append(string name, string value)
300 HtmlAttribute att = _ownernode._ownerdocument.CreateAttribute(name, value);
301 return Append(att);
304 /// <summary>
305 /// Inserts the specified attribute as the first node in the collection.
306 /// </summary>
307 /// <param name="newAttribute">The attribute to insert. May not be null.</param>
308 /// <returns>The prepended attribute.</returns>
309 public HtmlAttribute Prepend(HtmlAttribute newAttribute)
311 if (newAttribute == null)
313 throw new ArgumentNullException("newAttribute");
316 _hashitems[newAttribute.Name] = newAttribute;
317 newAttribute._ownernode = _ownernode;
318 _items.Insert(0, newAttribute);
320 _ownernode._innerchanged = true;
321 _ownernode._outerchanged = true;
322 return newAttribute;
325 /// <summary>
326 /// Removes the attribute at the specified index.
327 /// </summary>
328 /// <param name="index">The index of the attribute to remove.</param>
329 public void RemoveAt(int index)
331 HtmlAttribute att = (HtmlAttribute)_items[index];
332 _hashitems.Remove(att.Name);
333 _items.RemoveAt(index);
335 _ownernode._innerchanged = true;
336 _ownernode._outerchanged = true;
339 /// <summary>
340 /// Removes a given attribute from the list.
341 /// </summary>
342 /// <param name="attribute">The attribute to remove. May not be null.</param>
343 public void Remove(HtmlAttribute attribute)
345 if (attribute == null)
347 throw new ArgumentNullException("attribute");
349 int index = GetAttributeIndex(attribute);
350 if (index == -1)
352 throw new IndexOutOfRangeException();
354 RemoveAt(index);
357 /// <summary>
358 /// Removes an attribute from the list, using its name. If there are more than one attributes with this name, they will all be removed.
359 /// </summary>
360 /// <param name="name">The attribute's name. May not be null.</param>
361 public void Remove(string name)
363 if (name == null)
365 throw new ArgumentNullException("name");
368 string lname = name.ToLower();
369 for(int i=0;i<_items.Count;i++)
371 HtmlAttribute att = (HtmlAttribute)_items[i];
372 if (att.Name == lname)
374 RemoveAt(i);
379 /// <summary>
380 /// Remove all attributes in the list.
381 /// </summary>
382 public void RemoveAll()
384 _hashitems.Clear();
385 _items.Clear();
387 _ownernode._innerchanged = true;
388 _ownernode._outerchanged = true;
391 /// <summary>
392 /// Gets the number of elements actually contained in the list.
393 /// </summary>
394 public int Count
398 return _items.Count;
402 internal int GetAttributeIndex(HtmlAttribute attribute)
404 if (attribute == null)
406 throw new ArgumentNullException("attribute");
408 for(int i=0;i<_items.Count;i++)
410 if (((HtmlAttribute)_items[i])==attribute)
411 return i;
413 return -1;
416 internal int GetAttributeIndex(string name)
418 if (name == null)
420 throw new ArgumentNullException("name");
422 string lname = name.ToLower();
423 for(int i=0;i<_items.Count;i++)
425 if (((HtmlAttribute)_items[i]).Name==lname)
426 return i;
428 return -1;
431 /// <summary>
432 /// Gets a given attribute from the list using its name.
433 /// </summary>
434 public HtmlAttribute this[string name]
438 if (name == null)
440 throw new ArgumentNullException("name");
442 return _hashitems[name.ToLower()] as HtmlAttribute;
446 /// <summary>
447 /// Gets the attribute at the specified index.
448 /// </summary>
449 public HtmlAttribute this[int index]
453 return _items[index] as HtmlAttribute;
457 internal void Clear()
459 _hashitems.Clear();
460 _items.Clear();
463 /// <summary>
464 /// Returns an enumerator that can iterate through the list.
465 /// </summary>
466 /// <returns>An IEnumerator for the entire list.</returns>
467 public HtmlAttributeEnumerator GetEnumerator()
469 return new HtmlAttributeEnumerator(_items);
472 IEnumerator IEnumerable.GetEnumerator()
474 return GetEnumerator();
477 /// <summary>
478 /// Represents an enumerator that can iterate through the list.
479 /// </summary>
480 public class HtmlAttributeEnumerator: IEnumerator
482 int _index;
483 ArrayList _items;
485 internal HtmlAttributeEnumerator(ArrayList items)
487 _items = items;
488 _index = -1;
491 /// <summary>
492 /// Sets the enumerator to its initial position, which is before the first element in the collection.
493 /// </summary>
494 public void Reset()
496 _index = -1;
499 /// <summary>
500 /// Advances the enumerator to the next element of the collection.
501 /// </summary>
502 /// <returns>true if the enumerator was successfully advanced to the next element, false if the enumerator has passed the end of the collection.</returns>
503 public bool MoveNext()
505 _index++;
506 return (_index<_items.Count);
509 /// <summary>
510 /// Gets the current element in the collection.
511 /// </summary>
512 public HtmlAttribute Current
514 get
516 return (HtmlAttribute)(_items[_index]);
520 /// <summary>
521 /// Gets the current element in the collection.
522 /// </summary>
523 object IEnumerator.Current
525 get
527 return (Current);