// Description: Html Agility Pack - HTML Parsers, selectors, traversors, manupulators. // Website & Documentation: http://html-agility-pack.net // Forum & Issues: https://github.com/zzzprojects/html-agility-pack // License: https://github.com/zzzprojects/html-agility-pack/blob/master/LICENSE // More projects: http://www.zzzprojects.com/ // Copyright © ZZZ Projects Inc. 2014 - 2017. All rights reserved. using System; using System.Collections; using System.Collections.Generic; namespace HtmlAgilityPack { /// /// Represents a combined list and collection of HTML nodes. /// public class HtmlAttributeCollection : IList { #region Fields internal Dictionary Hashitems = new Dictionary(StringComparer.OrdinalIgnoreCase); private HtmlNode _ownernode; internal List items = new List(); #endregion #region Constructors internal HtmlAttributeCollection(HtmlNode ownernode) { _ownernode = ownernode; } #endregion #region IList Members /// /// Gets the number of elements actually contained in the list. /// public int Count { get { return items.Count; } } /// /// Gets readonly status of colelction /// public bool IsReadOnly { get { return false; } } /// /// Gets the attribute at the specified index. /// public HtmlAttribute this[int index] { get { return items[index]; } set { var oldValue = items[index]; items[index] = value; if (oldValue.Name != value.Name) { Hashitems.Remove(oldValue.Name); } Hashitems[value.Name] = value; value._ownernode = _ownernode; _ownernode.SetChanged(); } } /// /// Gets a given attribute from the list using its name. /// public HtmlAttribute this[string name] { get { if (name == null) { throw new ArgumentNullException("name"); } HtmlAttribute value; return Hashitems.TryGetValue(name, out value) ? value : null; } set { HtmlAttribute currentValue; if (!Hashitems.TryGetValue(name, out currentValue)) { Append(value); } else { this[items.IndexOf(currentValue)] = value; } } } /// /// Adds a new attribute to the collection with the given values /// /// /// public void Add(string name, string value) { Append(name, value); } /// /// Adds supplied item to collection /// /// public void Add(HtmlAttribute item) { Append(item); } /// Adds a range supplied items to collection. /// An IEnumerable<HtmlAttribute> of items to append to this. public void AddRange(IEnumerable items) { foreach (var item in items) { Append(item); } } /// Adds a range supplied items to collection using a dictionary. /// A Dictionary<string,string> of items to append to this. public void AddRange(Dictionary items) { foreach (var item in items) { Add(item.Key, item.Value); } } /// /// Explicit clear /// void ICollection.Clear() { items.Clear(); } /// /// Retreives existence of supplied item /// /// /// public bool Contains(HtmlAttribute item) { return items.Contains(item); } /// /// Copies collection to array /// /// /// public void CopyTo(HtmlAttribute[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); } /// /// Get Explicit enumerator /// /// IEnumerator IEnumerable.GetEnumerator() { return items.GetEnumerator(); } /// /// Explicit non-generic enumerator /// /// IEnumerator IEnumerable.GetEnumerator() { return items.GetEnumerator(); } /// /// Retrieves the index for the supplied item, -1 if not found /// /// /// public int IndexOf(HtmlAttribute item) { return items.IndexOf(item); } /// /// Inserts given item into collection at supplied index /// /// /// public void Insert(int index, HtmlAttribute item) { if (item == null) { throw new ArgumentNullException("item"); } Hashitems[item.Name] = item; item._ownernode = _ownernode; items.Insert(index, item); _ownernode.SetChanged(); } /// /// Explicit collection remove /// /// /// bool ICollection.Remove(HtmlAttribute item) { return items.Remove(item); } /// /// Removes the attribute at the specified index. /// /// The index of the attribute to remove. public void RemoveAt(int index) { HtmlAttribute att = items[index]; Hashitems.Remove(att.Name); items.RemoveAt(index); _ownernode.SetChanged(); } #endregion #region Public Methods /// /// Inserts the specified attribute as the last attribute in the collection. /// /// The attribute to insert. May not be null. /// The appended attribute. public HtmlAttribute Append(HtmlAttribute newAttribute) { if (_ownernode.NodeType == HtmlNodeType.Text || _ownernode.NodeType == HtmlNodeType.Comment) { throw new Exception("A Text or Comment node cannot have attributes."); } if (newAttribute == null) { throw new ArgumentNullException("newAttribute"); } Hashitems[newAttribute.Name] = newAttribute; newAttribute._ownernode = _ownernode; items.Add(newAttribute); _ownernode.SetChanged(); return newAttribute; } /// /// Creates and inserts a new attribute as the last attribute in the collection. /// /// The name of the attribute to insert. /// The appended attribute. public HtmlAttribute Append(string name) { HtmlAttribute att = _ownernode._ownerdocument.CreateAttribute(name); return Append(att); } /// /// Creates and inserts a new attribute as the last attribute in the collection. /// /// The name of the attribute to insert. /// The value of the attribute to insert. /// The appended attribute. public HtmlAttribute Append(string name, string value) { HtmlAttribute att = _ownernode._ownerdocument.CreateAttribute(name, value); return Append(att); } /// /// Checks for existance of attribute with given name /// /// /// public bool Contains(string name) { for (int i = 0; i < items.Count; i++) { if (String.Equals(items[i].Name, name, StringComparison.OrdinalIgnoreCase)) return true; } return false; } /// /// Inserts the specified attribute as the first node in the collection. /// /// The attribute to insert. May not be null. /// The prepended attribute. public HtmlAttribute Prepend(HtmlAttribute newAttribute) { Insert(0, newAttribute); return newAttribute; } /// /// Removes a given attribute from the list. /// /// The attribute to remove. May not be null. public void Remove(HtmlAttribute attribute) { if (attribute == null) { throw new ArgumentNullException("attribute"); } int index = GetAttributeIndex(attribute); if (index == -1) { throw new IndexOutOfRangeException(); } RemoveAt(index); } /// /// Removes an attribute from the list, using its name. If there are more than one attributes with this name, they will all be removed. /// /// The attribute's name. May not be null. public void Remove(string name) { if (name == null) { throw new ArgumentNullException("name"); } for (int i = 0; i < items.Count; i++) { HtmlAttribute att = items[i]; if (String.Equals(att.Name, name, StringComparison.OrdinalIgnoreCase)) { RemoveAt(i); } } } /// /// Remove all attributes in the list. /// public void RemoveAll() { Hashitems.Clear(); items.Clear(); _ownernode.SetChanged(); } #endregion #region LINQ Methods /// /// Returns all attributes with specified name. Handles case insentivity /// /// Name of the attribute /// public IEnumerable AttributesWithName(string attributeName) { for (int i = 0; i < items.Count; i++) { if (String.Equals(items[i].Name, attributeName, StringComparison.OrdinalIgnoreCase)) yield return items[i]; } } /// /// Removes all attributes from the collection /// public void Remove() { items.Clear(); } #endregion #region Internal Methods /// /// Clears the attribute collection /// internal void Clear() { Hashitems.Clear(); items.Clear(); } internal int GetAttributeIndex(HtmlAttribute attribute) { if (attribute == null) { throw new ArgumentNullException("attribute"); } for (int i = 0; i < items.Count; i++) { if ((items[i]) == attribute) return i; } return -1; } internal int GetAttributeIndex(string name) { if (name == null) { throw new ArgumentNullException("name"); } for (int i = 0; i < items.Count; i++) { if (String.Equals((items[i]).Name, name, StringComparison.OrdinalIgnoreCase)) return i; } return -1; } #endregion } }