NamedNodeMap
NamedNodeNap is a key/value pair of nodes that can be accessed by
numeric or string index.
using AngleSharp.Extensions;
using System;
using System.Collections;
using System.Collections.Generic;
namespace AngleSharp.Dom.Collections
{
internal sealed class NamedNodeMap : INamedNodeMap, IEnumerable<IAttr>, IEnumerable
{
private readonly List<Attr> _items;
private readonly WeakReference<Element> _owner;
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];
}
}
public int Length => _items.Count;
public NamedNodeMap(Element owner)
{
_items = new List<Attr>();
_owner = new WeakReference<Element>(owner);
}
internal void FastAddItem(Attr attr)
{
_items.Add(attr);
}
internal void RaiseChangedEvent(Attr attr, string newValue, string oldValue)
{
Element target = null;
if (_owner.TryGetTarget(out target))
target.AttributeChanged(attr.LocalName, attr.NamespaceUri, oldValue, newValue);
}
internal IAttr RemoveNamedItemOrDefault(string name, bool suppressMutationObservers)
{
for (int i = 0; i < _items.Count; i++) {
if (name.Is(_items[i].Name)) {
Attr attr = _items[i];
_items.RemoveAt(i);
attr.Container = null;
if (!suppressMutationObservers)
RaiseChangedEvent(attr, null, attr.Value);
return attr;
}
}
return null;
}
internal IAttr RemoveNamedItemOrDefault(string name)
{
return RemoveNamedItemOrDefault(name, false);
}
internal IAttr RemoveNamedItemOrDefault(string namespaceUri, string localName, bool suppressMutationObservers)
{
for (int i = 0; i < _items.Count; i++) {
if (localName.Is(_items[i].LocalName) && namespaceUri.Is(_items[i].NamespaceUri)) {
Attr attr = _items[i];
_items.RemoveAt(i);
attr.Container = null;
if (!suppressMutationObservers)
RaiseChangedEvent(attr, null, attr.Value);
return attr;
}
}
return null;
}
internal IAttr RemoveNamedItemOrDefault(string namespaceUri, string localName)
{
return RemoveNamedItemOrDefault(namespaceUri, localName, false);
}
public IAttr GetNamedItem(string name)
{
for (int i = 0; i < _items.Count; i++) {
if (name.Is(_items[i].Name))
return _items[i];
}
return null;
}
public IAttr GetNamedItem(string namespaceUri, string localName)
{
for (int i = 0; i < _items.Count; i++) {
if (localName.Is(_items[i].LocalName) && namespaceUri.Is(_items[i].NamespaceUri))
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 (name.Is(_items[i].Name)) {
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, bool suppressMutationObservers)
{
Attr attr = Prepare(item);
if (attr != null) {
string localName = item.LocalName;
string namespaceUri = item.NamespaceUri;
for (int i = 0; i < _items.Count; i++) {
if (localName.Is(_items[i].LocalName) && namespaceUri.Is(_items[i].NamespaceUri)) {
Attr attr2 = _items[i];
_items[i] = attr;
if (!suppressMutationObservers)
RaiseChangedEvent(attr, attr.Value, attr2.Value);
return attr2;
}
}
_items.Add(attr);
if (!suppressMutationObservers)
RaiseChangedEvent(attr, attr.Value, null);
}
return null;
}
public IAttr SetNamedItemWithNamespaceUri(IAttr item)
{
return SetNamedItemWithNamespaceUri(item, false);
}
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 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;
}
}
}