View Javadoc
1   /*
2    * Copyright (c) 2002-2025 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   */
29  public class DomAttr extends DomNamespaceNode implements Attr {
30  
31      private String value_;
32      private boolean specified_;
33  
34      /**
35       * Instantiate a new attribute.
36       *
37       * @param page the page that the attribute belongs to
38       * @param namespaceURI the namespace that defines the attribute name (may be {@code null})
39       * @param qualifiedName the name of the attribute
40       * @param value the value of the attribute
41       * @param specified {@code true} if this attribute was explicitly given a value in the source document,
42       *        or if the application changed the value of the attribute
43       */
44      public DomAttr(final SgmlPage page, final String namespaceURI, final String qualifiedName, final String value,
45          final boolean specified) {
46          super(namespaceURI, qualifiedName, page);
47  
48          if (value != null && value.isEmpty()) {
49              value_ = DomElement.ATTRIBUTE_VALUE_EMPTY;
50          }
51          else {
52              value_ = value;
53          }
54  
55          specified_ = specified;
56      }
57  
58      /**
59       * {@inheritDoc}
60       */
61      @Override
62      public short getNodeType() {
63          return ATTRIBUTE_NODE;
64      }
65  
66      /**
67       * {@inheritDoc}
68       */
69      @Override
70      public String getNodeName() {
71          return getName();
72      }
73  
74      /**
75       * {@inheritDoc}
76       */
77      @Override
78      public String getNodeValue() {
79          return getValue();
80      }
81  
82      /**
83       * {@inheritDoc}
84       */
85      @Override
86      public String getName() {
87          return getQualifiedName();
88      }
89  
90      /**
91       * {@inheritDoc}
92       */
93      @Override
94      public String getValue() {
95          return value_;
96      }
97  
98      /**
99       * {@inheritDoc}
100      */
101     @Override
102     public void setNodeValue(final String value) {
103         setValue(value);
104     }
105 
106     /**
107      * {@inheritDoc}
108      */
109     @Override
110     public void setValue(final String value) {
111         if (value != null
112                 && value.isEmpty()) {
113             value_ = DomElement.ATTRIBUTE_VALUE_EMPTY;
114         }
115         else {
116             value_ = value;
117         }
118         specified_ = true;
119     }
120 
121     /**
122      * {@inheritDoc}
123      */
124     @Override
125     public DomElement getOwnerElement() {
126         return (DomElement) getParentNode();
127     }
128 
129     /**
130      * {@inheritDoc}
131      */
132     @Override
133     public boolean getSpecified() {
134         return specified_;
135     }
136 
137     /**
138      * {@inheritDoc}
139      * Not yet implemented.
140      */
141     @Override
142     public TypeInfo getSchemaTypeInfo() {
143         throw new UnsupportedOperationException("DomAttr.getSchemaTypeInfo is not yet implemented.");
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     @Override
150     public boolean isId() {
151         return DomElement.ID_ATTRIBUTE.equals(getNodeName());
152     }
153 
154     /**
155      * {@inheritDoc}
156      */
157     @Override
158     public String toString() {
159         return getClass().getSimpleName() + "[name=" + getNodeName() + " value=" + getNodeValue() + "]";
160     }
161 
162     /**
163      * {@inheritDoc}
164      */
165     @Override
166     public String getCanonicalXPath() {
167         return getParentNode().getCanonicalXPath() + "/@" + getName();
168     }
169 
170     /**
171      * {@inheritDoc}
172      */
173     @Override
174     public String getTextContent() {
175         return getNodeValue();
176     }
177 
178     /**
179      * {@inheritDoc}
180      */
181     @Override
182     public void setTextContent(final String textContent) {
183         final boolean mappedElement =
184                 getOwnerDocument() instanceof HtmlPage
185                 && (DomElement.NAME_ATTRIBUTE.equals(getName()) || DomElement.ID_ATTRIBUTE.equals(getName()));
186         if (mappedElement) {
187             ((HtmlPage) getPage()).removeMappedElement(getOwnerElement(), false, false);
188         }
189         setValue(textContent);
190         if (mappedElement) {
191             ((HtmlPage) getPage()).addMappedElement(getOwnerElement(), false);
192         }
193     }
194 }