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