001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.jxpath.ri.model.dom;
019
020import org.apache.commons.jxpath.ri.Compiler;
021import org.apache.commons.jxpath.ri.QName;
022import org.apache.commons.jxpath.ri.compiler.NodeTest;
023import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
024import org.apache.commons.jxpath.ri.model.NodePointer;
025import org.apache.commons.jxpath.util.TypeUtils;
026import org.w3c.dom.Attr;
027
028/**
029 * A Pointer that points to a DOM {@link Attr} node. Because the underlying DOM Attr is not Serializable, neither is this pointer class truly so.
030 */
031public class DOMAttributePointer extends NodePointer {
032
033    private static final long serialVersionUID = 1115085175427555951L;
034
035    /**
036     * A DOM {@link Attr} node.
037     */
038    private final Attr attr;
039
040    /**
041     * Constructs a new DOMAttributePointer.
042     *
043     * @param parent pointer
044     * @param attr   pointed
045     */
046    public DOMAttributePointer(final NodePointer parent, final Attr attr) {
047        super(parent);
048        this.attr = attr;
049    }
050
051    @Override
052    public String asPath() {
053        final StringBuilder buffer = new StringBuilder();
054        if (parent != null) {
055            buffer.append(parent.asPath());
056            if (buffer.length() == 0 || buffer.charAt(buffer.length() - 1) != '/') {
057                buffer.append('/');
058            }
059        }
060        buffer.append('@');
061        buffer.append(getName());
062        return buffer.toString();
063    }
064
065    @Override
066    public int compareChildNodePointers(final NodePointer pointer1, final NodePointer pointer2) {
067        // Won't happen - attributes don't have children
068        return 0;
069    }
070
071    @Override
072    public boolean equals(final Object object) {
073        return object == this || object instanceof DOMAttributePointer && attr == ((DOMAttributePointer) object).attr;
074    }
075
076    @Override
077    public Object getBaseValue() {
078        return attr;
079    }
080
081    @Override
082    public Object getImmediateNode() {
083        return attr;
084    }
085
086    @Override
087    public int getLength() {
088        return 1;
089    }
090
091    @Override
092    public QName getName() {
093        return new QName(DOMNodePointer.getPrefix(attr), DOMNodePointer.getLocalName(attr));
094    }
095
096    @Override
097    public String getNamespaceURI() {
098        final String prefix = DOMNodePointer.getPrefix(attr);
099        return prefix == null ? null : parent.getNamespaceURI(prefix);
100    }
101
102    @Override
103    public Object getValue() {
104        final String value = attr.getValue();
105        if (value == null || value.isEmpty() && !attr.getSpecified()) {
106            return null;
107        }
108        return value;
109    }
110
111    @Override
112    public int hashCode() {
113        return System.identityHashCode(attr);
114    }
115
116    @Override
117    public boolean isActual() {
118        return true;
119    }
120
121    @Override
122    public boolean isCollection() {
123        return false;
124    }
125
126    @Override
127    public boolean isLeaf() {
128        return true;
129    }
130
131    @Override
132    public void remove() {
133        attr.getOwnerElement().removeAttributeNode(attr);
134    }
135
136    /**
137     * Sets the value of this attribute.
138     *
139     * @param value to set
140     */
141    @Override
142    public void setValue(final Object value) {
143        attr.setValue((String) TypeUtils.convert(value, String.class));
144    }
145
146    @Override
147    public boolean testNode(final NodeTest nodeTest) {
148        return nodeTest == null || nodeTest instanceof NodeTypeTest && ((NodeTypeTest) nodeTest).getNodeType() == Compiler.NODE_TYPE_NODE;
149    }
150}