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
24namespace Poco {
25namespace XML {
26
27
28Element::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
36Element::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
52Element::~Element()
53{
54 if (_pFirstAttr) _pFirstAttr->release();
55}
56
57
58const 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
68void 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
85void Element::removeAttribute(const XMLString& name)
86{
87 Attr* pAttr = getAttributeNode(name);
88 if (pAttr) removeAttributeNode(pAttr);
89}
90
91
92Attr* 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
100Attr* 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
128Attr* 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
154Attr* 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
175NodeList* Element::getElementsByTagName(const XMLString& name) const
176{
177 return new ElementsByTagNameList(this, name);
178}
179
180
181NodeList* Element::getElementsByTagNameNS(const XMLString& namespaceURI, const XMLString& localName) const
182{
183 return new ElementsByTagNameListNS(this, namespaceURI, localName);
184}
185
186
187void 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
211const XMLString& Element::nodeName() const
212{
213 return tagName();
214}
215
216
217NamedNodeMap* Element::attributes() const
218{
219 return new AttrMap(const_cast<Element*>(this));
220}
221
222
223unsigned short Element::nodeType() const
224{
225 return Node::ELEMENT_NODE;
226}
227
228
229const 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
239void 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
256void Element::removeAttributeNS(const XMLString& namespaceURI, const XMLString& localName)
257{
258 Attr* pAttr = getAttributeNodeNS(namespaceURI, localName);
259 if (pAttr) removeAttributeNode(pAttr);
260}
261
262
263Attr* 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
271Attr* 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
299bool Element::hasAttribute(const XMLString& name) const
300{
301 return getAttributeNode(name) != 0;
302}
303
304
305bool Element::hasAttributeNS(const XMLString& namespaceURI, const XMLString& localName) const
306{
307 return getAttributeNodeNS(namespaceURI, localName) != 0;
308}
309
310
311const XMLString& Element::namespaceURI() const
312{
313 return _name.namespaceURI();
314}
315
316
317XMLString Element::prefix() const
318{
319 return _name.prefix();
320}
321
322
323const XMLString& Element::localName() const
324{
325 return _name.localName();
326}
327
328
329bool Element::hasAttributes() const
330{
331 return _pFirstAttr != 0;
332}
333
334
335XMLString 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
348Element* 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
357Element* 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
366void 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
378void 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
390Node* 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
406Element* 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
425Element* 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