AngleSharp by AngleSharp

<PackageReference Include="AngleSharp" Version="0.9.3" />

 NamedNodeMap

NamedNodeNap is a key/value pair of nodes that can be accessed by numeric or string index.
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; namespace AngleSharp.Dom.Collections { [DebuggerStepThrough] internal sealed class NamedNodeMap : INamedNodeMap, IEnumerable<IAttr>, IEnumerable { private readonly List<Attr> _items; private readonly WeakReference<Element> _owner; private readonly Dictionary<string, Action<string>> _attributeHandlers; public IAttr this[string name] { get { return GetNamedItem(name); } } public IAttr this[int index] { get { if (index < 0 || index >= _items.Count) return null; return _items[index]; } } internal Element Owner { get { Element target = null; _owner.TryGetTarget(out target); return target; } } public int Length => _items.Count; public NamedNodeMap(Element owner) { _items = new List<Attr>(); _owner = new WeakReference<Element>(owner); _attributeHandlers = new Dictionary<string, Action<string>>(); } internal void FastAddItem(Attr attr) { _items.Add(attr); if (attr.NamespaceUri == null) CallHandlers(attr.LocalName, attr.Value); } internal void RaiseChangedEvent(Attr attr, string newValue, string oldValue) { Element owner = Owner; if (attr.NamespaceUri == null) CallHandlers(attr.LocalName, newValue); owner?.AttributeChanged(attr.LocalName, attr.NamespaceUri, oldValue); } internal void SetHandler(string name, Action<string> handler) { _attributeHandlers[name] = handler; } internal void AddHandler(string name, Action<string> handler) { if (handler != null) { Action<string> value = null; if (_attributeHandlers.TryGetValue(name, out value)) handler = (Action<string>)Delegate.Combine(handler, value); _attributeHandlers[name] = handler; } } internal Action<string> RemoveHandler(string name) { Action<string> value = null; if (_attributeHandlers.TryGetValue(name, out value)) _attributeHandlers.Remove(name); return value; } internal IAttr RemoveNamedItemOrDefault(string name) { for (int i = 0; i < _items.Count; i++) { if (string.Equals(_items[i].Name, name, StringComparison.Ordinal)) { Attr attr = _items[i]; _items.RemoveAt(i); attr.Container = null; RaiseChangedEvent(attr, null, attr.Value); return attr; } } return null; } internal IAttr RemoveNamedItemOrDefault(string namespaceUri, string localName) { for (int i = 0; i < _items.Count; i++) { if (string.Equals(_items[i].LocalName, localName, StringComparison.Ordinal) && string.Equals(_items[i].NamespaceUri, namespaceUri, StringComparison.Ordinal)) { Attr attr = _items[i]; _items.RemoveAt(i); attr.Container = null; RaiseChangedEvent(attr, null, attr.Value); return attr; } } return null; } public IAttr GetNamedItem(string name) { for (int i = 0; i < _items.Count; i++) { if (string.Equals(_items[i].Name, name, StringComparison.Ordinal)) return _items[i]; } return null; } public IAttr GetNamedItem(string namespaceUri, string localName) { for (int i = 0; i < _items.Count; i++) { if (string.Equals(_items[i].LocalName, localName, StringComparison.Ordinal) && string.Equals(_items[i].NamespaceUri, namespaceUri, StringComparison.Ordinal)) return _items[i]; } return null; } public IAttr SetNamedItem(IAttr item) { Attr attr = Prepare(item); if (attr != null) { string name = item.Name; for (int i = 0; i < _items.Count; i++) { if (string.Equals(_items[i].Name, name, StringComparison.Ordinal)) { Attr attr2 = _items[i]; _items[i] = attr; RaiseChangedEvent(attr, attr.Value, attr2.Value); return attr2; } } _items.Add(attr); RaiseChangedEvent(attr, attr.Value, null); } return null; } public IAttr SetNamedItemWithNamespaceUri(IAttr item) { Attr attr = Prepare(item); if (attr != null) { string localName = item.LocalName; string namespaceUri = item.NamespaceUri; for (int i = 0; i < _items.Count; i++) { if (string.Equals(_items[i].LocalName, localName, StringComparison.Ordinal) && string.Equals(_items[i].NamespaceUri, namespaceUri, StringComparison.Ordinal)) { Attr attr2 = _items[i]; _items[i] = attr; RaiseChangedEvent(attr, attr.Value, attr2.Value); return attr2; } } _items.Add(attr); RaiseChangedEvent(attr, attr.Value, null); } return null; } public IAttr RemoveNamedItem(string name) { IAttr attr = RemoveNamedItemOrDefault(name); if (attr == null) throw new DomException(DomError.NotFound); return attr; } public IAttr RemoveNamedItem(string namespaceUri, string localName) { IAttr attr = RemoveNamedItemOrDefault(namespaceUri, localName); if (attr == null) throw new DomException(DomError.NotFound); return attr; } public IEnumerator<IAttr> GetEnumerator() { return _items.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _items.GetEnumerator(); } private void CallHandlers(string name, string value) { Action<string> value2 = null; if (_attributeHandlers.TryGetValue(name, out value2)) value2(value); } private Attr Prepare(IAttr item) { Attr attr = item as Attr; if (attr != null) { if (attr.Container == this) return null; if (attr.Container != null) throw new DomException(DomError.InUse); attr.Container = this; } return attr; } } }