1 //
2 // Element.cpp
3 //
4 // Library: XML
5 // Package: DOM
6 // Module: DOM
7 //
8 // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9 // and Contributors.
10 //
11 // SPDX-License-Identifier: BSL-1.0
12 //
13
14
15 #include "Poco/DOM/Element.h"
16 #include "Poco/DOM/Document.h"
17 #include "Poco/DOM/Attr.h"
18 #include "Poco/DOM/DOMException.h"
19 #include "Poco/DOM/ElementsByTagNameList.h"
20 #include "Poco/DOM/Text.h"
21 #include "Poco/DOM/AttrMap.h"
22
23
24 namespace Poco {
25 namespace XML {
26
27
Element(Document * pOwnerDocument,const XMLString & namespaceURI,const XMLString & localName,const XMLString & qname)28 Element::Element(Document* pOwnerDocument, const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname):
29 AbstractContainerNode(pOwnerDocument),
30 _name(pOwnerDocument->namePool().insert(qname, namespaceURI, localName)),
31 _pFirstAttr(0)
32 {
33 }
34
35
Element(Document * pOwnerDocument,const Element & element)36 Element::Element(Document* pOwnerDocument, const Element& element):
37 AbstractContainerNode(pOwnerDocument, element),
38 _name(pOwnerDocument->namePool().insert(element._name)),
39 _pFirstAttr(0)
40 {
41 Attr* pAttr = element._pFirstAttr;
42 while (pAttr)
43 {
44 Attr* pClonedAttr = static_cast<Attr*>(pAttr->copyNode(false, pOwnerDocument));
45 setAttributeNode(pClonedAttr);
46 pClonedAttr->release();
47 pAttr = static_cast<Attr*>(pAttr->_pNext);
48 }
49 }
50
51
~Element()52 Element::~Element()
53 {
54 if (_pFirstAttr) _pFirstAttr->release();
55 }
56
57
getAttribute(const XMLString & name) const58 const XMLString& Element::getAttribute(const XMLString& name) const
59 {
60 Attr* pAttr = getAttributeNode(name);
61 if (pAttr)
62 return pAttr->getValue();
63 else
64 return EMPTY_STRING;
65 }
66
67
setAttribute(const XMLString & name,const XMLString & value)68 void Element::setAttribute(const XMLString& name, const XMLString& value)
69 {
70 Attr* pAttr = getAttributeNode(name);
71 if (pAttr)
72 {
73 pAttr->setValue(value);
74 }
75 else
76 {
77 pAttr = ownerDocument()->createAttribute(name);
78 pAttr->setValue(value);
79 setAttributeNode(pAttr);
80 pAttr->release();
81 }
82 }
83
84
removeAttribute(const XMLString & name)85 void Element::removeAttribute(const XMLString& name)
86 {
87 Attr* pAttr = getAttributeNode(name);
88 if (pAttr) removeAttributeNode(pAttr);
89 }
90
91
getAttributeNode(const XMLString & name) const92 Attr* Element::getAttributeNode(const XMLString& name) const
93 {
94 Attr* pAttr = _pFirstAttr;
95 while (pAttr && pAttr->_name.qname() != name) pAttr = static_cast<Attr*>(pAttr->_pNext);
96 return pAttr;
97 }
98
99
setAttributeNode(Attr * newAttr)100 Attr* Element::setAttributeNode(Attr* newAttr)
101 {
102 poco_check_ptr (newAttr);
103
104 if (newAttr->ownerDocument() != ownerDocument())
105 throw DOMException(DOMException::WRONG_DOCUMENT_ERR);
106 if (newAttr->ownerElement())
107 throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR);
108
109 Attr* oldAttr = getAttributeNode(newAttr->name());
110 if (oldAttr) removeAttributeNode(oldAttr);
111
112 Attr* pCur = _pFirstAttr;
113 if (pCur)
114 {
115 while (pCur->_pNext) pCur = static_cast<Attr*>(pCur->_pNext);
116 pCur->_pNext = newAttr;
117 }
118 else _pFirstAttr = newAttr;
119 newAttr->duplicate();
120 newAttr->_pParent = this;
121 if (_pOwner->events())
122 dispatchAttrModified(newAttr, MutationEvent::ADDITION, EMPTY_STRING, newAttr->getValue());
123
124 return oldAttr;
125 }
126
127
removeAttributeNode(Attr * oldAttr)128 Attr* Element::removeAttributeNode(Attr* oldAttr)
129 {
130 poco_check_ptr (oldAttr);
131
132 if (_pOwner->events())
133 dispatchAttrModified(oldAttr, MutationEvent::REMOVAL, oldAttr->getValue(), EMPTY_STRING);
134
135 if (oldAttr != _pFirstAttr)
136 {
137 Attr* pCur = _pFirstAttr;
138 while (pCur->_pNext != oldAttr) pCur = static_cast<Attr*>(pCur->_pNext);
139 if (pCur)
140 {
141 pCur->_pNext = static_cast<Attr*>(pCur->_pNext->_pNext);
142 }
143 else throw DOMException(DOMException::NOT_FOUND_ERR);
144 }
145 else _pFirstAttr = static_cast<Attr*>(_pFirstAttr->_pNext);
146 oldAttr->_pNext = 0;
147 oldAttr->_pParent = 0;
148 oldAttr->autoRelease();
149
150 return oldAttr;
151 }
152
153
addAttributeNodeNP(Attr * oldAttr,Attr * newAttr)154 Attr* Element::addAttributeNodeNP(Attr* oldAttr, Attr* newAttr)
155 {
156 newAttr->_pParent = this;
157 if (oldAttr)
158 {
159 oldAttr->_pNext = newAttr;
160 }
161 else if (_pFirstAttr)
162 {
163 newAttr->_pNext = _pFirstAttr;
164 _pFirstAttr = newAttr;
165 }
166 else
167 {
168 _pFirstAttr = newAttr;
169 }
170 newAttr->duplicate();
171 return newAttr;
172 }
173
174
getElementsByTagName(const XMLString & name) const175 NodeList* Element::getElementsByTagName(const XMLString& name) const
176 {
177 return new ElementsByTagNameList(this, name);
178 }
179
180
getElementsByTagNameNS(const XMLString & namespaceURI,const XMLString & localName) const181 NodeList* Element::getElementsByTagNameNS(const XMLString& namespaceURI, const XMLString& localName) const
182 {
183 return new ElementsByTagNameListNS(this, namespaceURI, localName);
184 }
185
186
normalize()187 void Element::normalize()
188 {
189 Node* pCur = firstChild();
190 while (pCur)
191 {
192 if (pCur->nodeType() == Node::ELEMENT_NODE)
193 {
194 pCur->normalize();
195 }
196 else if (pCur->nodeType() == Node::TEXT_NODE)
197 {
198 Node* pNext = pCur->nextSibling();
199 while (pNext && pNext->nodeType() == Node::TEXT_NODE)
200 {
201 static_cast<Text*>(pCur)->appendData(pNext->nodeValue());
202 removeChild(pNext);
203 pNext = pCur->nextSibling();
204 }
205 }
206 pCur = pCur->nextSibling();
207 }
208 }
209
210
nodeName() const211 const XMLString& Element::nodeName() const
212 {
213 return tagName();
214 }
215
216
attributes() const217 NamedNodeMap* Element::attributes() const
218 {
219 return new AttrMap(const_cast<Element*>(this));
220 }
221
222
nodeType() const223 unsigned short Element::nodeType() const
224 {
225 return Node::ELEMENT_NODE;
226 }
227
228
getAttributeNS(const XMLString & namespaceURI,const XMLString & localName) const229 const XMLString& Element::getAttributeNS(const XMLString& namespaceURI, const XMLString& localName) const
230 {
231 Attr* pAttr = getAttributeNodeNS(namespaceURI, localName);
232 if (pAttr)
233 return pAttr->getValue();
234 else
235 return EMPTY_STRING;
236 }
237
238
setAttributeNS(const XMLString & namespaceURI,const XMLString & qualifiedName,const XMLString & value)239 void Element::setAttributeNS(const XMLString& namespaceURI, const XMLString& qualifiedName, const XMLString& value)
240 {
241 Attr* pAttr = getAttributeNodeNS(namespaceURI, qualifiedName);
242 if (pAttr)
243 {
244 pAttr->setValue(value);
245 }
246 else
247 {
248 pAttr = _pOwner->createAttributeNS(namespaceURI, qualifiedName);
249 pAttr->setValue(value);
250 setAttributeNodeNS(pAttr);
251 pAttr->release();
252 }
253 }
254
255
removeAttributeNS(const XMLString & namespaceURI,const XMLString & localName)256 void Element::removeAttributeNS(const XMLString& namespaceURI, const XMLString& localName)
257 {
258 Attr* pAttr = getAttributeNodeNS(namespaceURI, localName);
259 if (pAttr) removeAttributeNode(pAttr);
260 }
261
262
getAttributeNodeNS(const XMLString & namespaceURI,const XMLString & localName) const263 Attr* Element::getAttributeNodeNS(const XMLString& namespaceURI, const XMLString& localName) const
264 {
265 Attr* pAttr = _pFirstAttr;
266 while (pAttr && (pAttr->_name.namespaceURI() != namespaceURI || pAttr->_name.localName() != localName)) pAttr = static_cast<Attr*>(pAttr->_pNext);
267 return pAttr;
268 }
269
270
setAttributeNodeNS(Attr * newAttr)271 Attr* Element::setAttributeNodeNS(Attr* newAttr)
272 {
273 poco_check_ptr (newAttr);
274
275 if (newAttr->ownerDocument() != ownerDocument())
276 throw DOMException(DOMException::WRONG_DOCUMENT_ERR);
277 if (newAttr->ownerElement())
278 throw DOMException(DOMException::INUSE_ATTRIBUTE_ERR);
279
280 Attr* oldAttr = getAttributeNodeNS(newAttr->namespaceURI(), newAttr->localName());
281 if (oldAttr) removeAttributeNode(oldAttr);
282
283 Attr* pCur = _pFirstAttr;
284 if (pCur)
285 {
286 while (pCur->_pNext) pCur = static_cast<Attr*>(pCur->_pNext);
287 pCur->_pNext = newAttr;
288 }
289 else _pFirstAttr = newAttr;
290 newAttr->_pParent = this;
291 newAttr->duplicate();
292 if (_pOwner->events())
293 dispatchAttrModified(newAttr, MutationEvent::ADDITION, EMPTY_STRING, newAttr->getValue());
294
295 return oldAttr;
296 }
297
298
hasAttribute(const XMLString & name) const299 bool Element::hasAttribute(const XMLString& name) const
300 {
301 return getAttributeNode(name) != 0;
302 }
303
304
hasAttributeNS(const XMLString & namespaceURI,const XMLString & localName) const305 bool Element::hasAttributeNS(const XMLString& namespaceURI, const XMLString& localName) const
306 {
307 return getAttributeNodeNS(namespaceURI, localName) != 0;
308 }
309
310
namespaceURI() const311 const XMLString& Element::namespaceURI() const
312 {
313 return _name.namespaceURI();
314 }
315
316
prefix() const317 XMLString Element::prefix() const
318 {
319 return _name.prefix();
320 }
321
322
localName() const323 const XMLString& Element::localName() const
324 {
325 return _name.localName();
326 }
327
328
hasAttributes() const329 bool Element::hasAttributes() const
330 {
331 return _pFirstAttr != 0;
332 }
333
334
innerText() const335 XMLString Element::innerText() const
336 {
337 XMLString result;
338 Node* pChild = firstChild();
339 while (pChild)
340 {
341 result.append(pChild->innerText());
342 pChild = pChild->nextSibling();
343 }
344 return result;
345 }
346
347
getChildElement(const XMLString & name) const348 Element* Element::getChildElement(const XMLString& name) const
349 {
350 Node* pNode = firstChild();
351 while (pNode && !(pNode->nodeType() == Node::ELEMENT_NODE && pNode->nodeName() == name))
352 pNode = pNode->nextSibling();
353 return static_cast<Element*>(pNode);
354 }
355
356
getChildElementNS(const XMLString & namespaceURI,const XMLString & localName) const357 Element* Element::getChildElementNS(const XMLString& namespaceURI, const XMLString& localName) const
358 {
359 Node* pNode = firstChild();
360 while (pNode && !(pNode->nodeType() == Node::ELEMENT_NODE && pNode->namespaceURI() == namespaceURI && pNode->localName() == localName))
361 pNode = pNode->nextSibling();
362 return static_cast<Element*>(pNode);
363 }
364
365
dispatchNodeRemovedFromDocument()366 void Element::dispatchNodeRemovedFromDocument()
367 {
368 AbstractContainerNode::dispatchNodeRemovedFromDocument();
369 Attr* pAttr = _pFirstAttr;
370 while (pAttr)
371 {
372 pAttr->dispatchNodeRemovedFromDocument();
373 pAttr = static_cast<Attr*>(pAttr->_pNext);
374 }
375 }
376
377
dispatchNodeInsertedIntoDocument()378 void Element::dispatchNodeInsertedIntoDocument()
379 {
380 AbstractContainerNode::dispatchNodeInsertedIntoDocument();
381 Attr* pAttr = _pFirstAttr;
382 while (pAttr)
383 {
384 pAttr->dispatchNodeInsertedIntoDocument();
385 pAttr = static_cast<Attr*>(pAttr->_pNext);
386 }
387 }
388
389
copyNode(bool deep,Document * pOwnerDocument) const390 Node* Element::copyNode(bool deep, Document* pOwnerDocument) const
391 {
392 Element* pClone = new Element(pOwnerDocument, *this);
393 if (deep)
394 {
395 Node* pNode = firstChild();
396 while (pNode)
397 {
398 pClone->appendChild(static_cast<AbstractNode*>(pNode)->copyNode(true, pOwnerDocument))->release();
399 pNode = pNode->nextSibling();
400 }
401 }
402 return pClone;
403 }
404
405
getElementById(const XMLString & elementId,const XMLString & idAttribute) const406 Element* Element::getElementById(const XMLString& elementId, const XMLString& idAttribute) const
407 {
408 if (getAttribute(idAttribute) == elementId)
409 return const_cast<Element*>(this);
410
411 Node* pNode = firstChild();
412 while (pNode)
413 {
414 if (pNode->nodeType() == Node::ELEMENT_NODE)
415 {
416 Element* pResult = static_cast<Element*>(pNode)->getElementById(elementId, idAttribute);
417 if (pResult) return pResult;
418 }
419 pNode = pNode->nextSibling();
420 }
421 return 0;
422 }
423
424
getElementByIdNS(const XMLString & elementId,const XMLString & idAttributeURI,const XMLString & idAttributeLocalName) const425 Element* Element::getElementByIdNS(const XMLString& elementId, const XMLString& idAttributeURI, const XMLString& idAttributeLocalName) const
426 {
427 if (getAttributeNS(idAttributeURI, idAttributeLocalName) == elementId)
428 return const_cast<Element*>(this);
429
430 Node* pNode = firstChild();
431 while (pNode)
432 {
433 if (pNode->nodeType() == Node::ELEMENT_NODE)
434 {
435 Element* pResult = static_cast<Element*>(pNode)->getElementByIdNS(elementId, idAttributeURI, idAttributeLocalName);
436 if (pResult) return pResult;
437 }
438 pNode = pNode->nextSibling();
439 }
440 return 0;
441 }
442
443
444 } } // namespace Poco::XML
445