/* eXist Open Source Native XML Database * Copyright (C) 2001-2014 The eXist Project * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id: */ package org.exist.dom; import org.exist.util.hashtable.Object2ObjectHashMap; import org.w3c.dom.DOMException; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import java.util.ArrayList; import java.util.List; /** * @author Adam Retter <adam.retter@googlemail.com> */ public class NamedNodeMapImpl implements NamedNodeMap { // NamedNodeMap is used by attributes, and it is often // rare that an element has more then 10 attributes private static final int DEFAULT_SIZE = 10; private final IndexedHashMap<QName, Node> namedNodes = new IndexedHashMap<>(DEFAULT_SIZE); @Override public Node getNamedItem(final String name) { return namedNodes.get(new QName(name)); } @Override public Node setNamedItem(final Node arg) throws DOMException { return namedNodes.put(new QName(arg.getNodeName()), arg); } /** * Adds an INode to the NamedNodeMap * * The INode#getQName method is called * to get the name for the map item * * @return The previous node of the same name if it exists */ public Node setNamedItem(final INode arg) throws DOMException { return namedNodes.put(arg.getQName(), arg); } @Override public Node removeNamedItem(final String name) throws DOMException { return remove(new QName(name)); } @Override public Node item(final int index) { return namedNodes.get(index); } @Override public int getLength() { return namedNodes.size(); } @Override public Node getNamedItemNS(final String namespaceURI, final String localName) throws DOMException { return namedNodes.get(new QName(localName, namespaceURI)); } @Override public Node setNamedItemNS(final Node arg) throws DOMException { return namedNodes.put(new QName(arg.getLocalName(), arg.getNamespaceURI()), arg); } @Override public Node removeNamedItemNS(final String namespaceURI, final String localName) throws DOMException { return remove(new QName(localName, namespaceURI)); } private Node remove(final QName qname) throws DOMException { final Node previous = namedNodes.remove(qname); if(previous != null) { return previous; } else { throw new DOMException(DOMException.NOT_FOUND_ERR, "No such named value is present in the map"); } } private static final class IndexedHashMap<K, V> { private final Object2ObjectHashMap<K, V> map; private final List<K> keys; public IndexedHashMap(final int initialSize) { this.map = new Object2ObjectHashMap<>(initialSize); this.keys = new ArrayList<>(initialSize); } public final V put(final K key, final V value) { final V current = map.get(key); map.put(key, value); if(current == null) { keys.add(key); } return current; } public final V get(final K key) { return map.get(key); } public final V get(final int index) { return map.get(keys.get(index)); } /** * @return The removed value or null if there is * no value for the key in the nap */ public final V remove(final K key) { if(keys.remove(key)) { return map.remove(key); } else { return null; } } public final int size() { return keys.size(); } } }