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;
}
}
}