View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import org.htmlunit.SgmlPage;
18  import org.w3c.dom.Attr;
19  import org.w3c.dom.TypeInfo;
20  
21  /**
22   * An attribute of an element. Attributes are stored in {@link HtmlElement},
23   * but the XPath engine expects attributes to be in a {@link DomNode}.
24   *
25   * @author Denis N. Antonioli
26   * @author David K. Taylor
27   * @author Ahmed Ashour
28   * @author Ronald Brill
29   */
30  public class DomAttr extends DomNamespaceNode implements Attr {
31  
32      private String value_;
33      private boolean specified_;
34  
35      /**
36       * Instantiate a new attribute.
37       *
38       * @param page the page that the attribute belongs to
39       * @param namespaceURI the namespace that defines the attribute name (maybe {@code null})
40       * @param qualifiedName the name of the attribute
41       * @param value the value of the attribute
42       * @param specified {@code true} if this attribute was explicitly given a value in the source document,
43       *        or if the application changed the value of the attribute
44       */
45      public DomAttr(final SgmlPage page, final String namespaceURI, final String qualifiedName, final String value,
46          final boolean specified) {
47          super(namespaceURI, qualifiedName, page);
48  
49          if (value != null && value.isEmpty()) {
50              value_ = DomElement.ATTRIBUTE_VALUE_EMPTY;
51          }
52          else {
53              value_ = value;
54          }
55  
56          specified_ = specified;
57      }
58  
59      /**
60       * {@inheritDoc}
61       */
62      @Override
63      public short getNodeType() {
64          return ATTRIBUTE_NODE;
65      }
66  
67      /**
68       * {@inheritDoc}
69       */
70      @Override
71      public String getNodeName() {
72          return getName();
73      }
74  
75      /**
76       * {@inheritDoc}
77       */
78      @Override
79      public String getNodeValue() {
80          return getValue();
81      }
82  
83      /**
84       * {@inheritDoc}
85       */
86      @Override
87      public String getName() {
88          return getQualifiedName();
89      }
90  
91      /**
92       * {@inheritDoc}
93       */
94      @Override
95      public String getValue() {
96          return value_;
97      }
98  
99      /**
100      * {@inheritDoc}
101      */
102     @Override
103     public void setNodeValue(final String value) {
104         setValue(value);
105     }
106 
107     /**
108      * {@inheritDoc}
109      */
110     @Override
111     public void setValue(final String value) {
112         if (value != null
113                 && value.isEmpty()) {
114             value_ = DomElement.ATTRIBUTE_VALUE_EMPTY;
115         }
116         else {
117             value_ = value;
118         }
119         specified_ = true;
120     }
121 
122     /**
123      * {@inheritDoc}
124      */
125     @Override
126     public DomElement getOwnerElement() {
127         return (DomElement) getParentNode();
128     }
129 
130     /**
131      * {@inheritDoc}
132      */
133     @Override
134     public boolean getSpecified() {
135         return specified_;
136     }
137 
138     /**
139      * {@inheritDoc}
140      * Not yet implemented.
141      */
142     @Override
143     public TypeInfo getSchemaTypeInfo() {
144         throw new UnsupportedOperationException("DomAttr.getSchemaTypeInfo is not yet implemented.");
145     }
146 
147     /**
148      * {@inheritDoc}
149      */
150     @Override
151     public boolean isId() {
152         return DomElement.ID_ATTRIBUTE.equals(getNodeName());
153     }
154 
155     /**
156      * {@inheritDoc}
157      */
158     @Override
159     public String toString() {
160         return getClass().getSimpleName() + "[name=" + getNodeName() + " value=" + getNodeValue() + "]";
161     }
162 
163     /**
164      * {@inheritDoc}
165      */
166     @Override
167     public String getCanonicalXPath() {
168         return getParentNode().getCanonicalXPath() + "/@" + getName();
169     }
170 
171     /**
172      * {@inheritDoc}
173      */
174     @Override
175     public String getTextContent() {
176         return getNodeValue();
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     @Override
183     public void setTextContent(final String textContent) {
184         final boolean mappedElement =
185                 getOwnerDocument() instanceof HtmlPage
186                 && (DomElement.NAME_ATTRIBUTE.equals(getName()) || DomElement.ID_ATTRIBUTE.equals(getName()));
187         if (mappedElement) {
188             ((HtmlPage) getPage()).removeMappedElement(getOwnerElement(), false, false);
189         }
190         setValue(textContent);
191         if (mappedElement) {
192             ((HtmlPage) getPage()).addMappedElement(getOwnerElement(), false);
193         }
194     }
195 }