1//
2// DOMBuilder.cpp
3//
4// Library: XML
5// Package: DOM
6// Module: DOMBuilder
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/DOMBuilder.h"
16#include "Poco/DOM/Document.h"
17#include "Poco/DOM/DocumentType.h"
18#include "Poco/DOM/CharacterData.h"
19#include "Poco/DOM/Text.h"
20#include "Poco/DOM/Comment.h"
21#include "Poco/DOM/CDATASection.h"
22#include "Poco/DOM/Element.h"
23#include "Poco/DOM/Attr.h"
24#include "Poco/DOM/Entity.h"
25#include "Poco/DOM/EntityReference.h"
26#include "Poco/DOM/Notation.h"
27#include "Poco/DOM/ProcessingInstruction.h"
28#include "Poco/DOM/AutoPtr.h"
29#include "Poco/SAX/XMLReader.h"
30#include "Poco/SAX/AttributesImpl.h"
31
32
33namespace Poco {
34namespace XML {
35
36
37const XMLString DOMBuilder::EMPTY_STRING;
38
39
40DOMBuilder::DOMBuilder(XMLReader& xmlReader, NamePool* pNamePool):
41 _xmlReader(xmlReader),
42 _pNamePool(pNamePool),
43 _pDocument(0),
44 _pParent(0),
45 _pPrevious(0),
46 _inCDATA(false),
47 _namespaces(true)
48{
49 _xmlReader.setContentHandler(this);
50 _xmlReader.setDTDHandler(this);
51 _xmlReader.setProperty(XMLReader::PROPERTY_LEXICAL_HANDLER, static_cast<LexicalHandler*>(this));
52
53 if (_pNamePool) _pNamePool->duplicate();
54}
55
56
57DOMBuilder::~DOMBuilder()
58{
59 if (_pNamePool) _pNamePool->release();
60}
61
62
63Document* DOMBuilder::parse(const XMLString& uri)
64{
65 setupParse();
66 _pDocument->suspendEvents();
67 try
68 {
69 _xmlReader.parse(uri);
70 }
71 catch (...)
72 {
73 _pDocument->release();
74 _pDocument = 0;
75 _pParent = 0;
76 _pPrevious = 0;
77 throw;
78 }
79 _pDocument->resumeEvents();
80 _pDocument->collectGarbage();
81 return _pDocument;
82}
83
84
85Document* DOMBuilder::parse(InputSource* pInputSource)
86{
87 setupParse();
88 _pDocument->suspendEvents();
89 try
90 {
91 _xmlReader.parse(pInputSource);
92 }
93 catch (...)
94 {
95 _pDocument->release();
96 _pDocument = 0;
97 _pParent = 0;
98 _pPrevious = 0;
99 throw;
100 }
101 _pDocument->resumeEvents();
102 _pDocument->collectGarbage();
103 return _pDocument;
104}
105
106
107Document* DOMBuilder::parseMemoryNP(const char* xml, std::size_t size)
108{
109 setupParse();
110 _pDocument->suspendEvents();
111 try
112 {
113 _xmlReader.parseMemoryNP(xml, size);
114 }
115 catch (...)
116 {
117 _pDocument->release();
118 _pDocument = 0;
119 _pParent = 0;
120 _pPrevious = 0;
121 throw;
122 }
123 _pDocument->resumeEvents();
124 _pDocument->collectGarbage();
125 return _pDocument;
126}
127
128
129void DOMBuilder::setupParse()
130{
131 _pDocument = new Document(_pNamePool);
132 _pParent = _pDocument;
133 _pPrevious = 0;
134 _inCDATA = false;
135 _namespaces = _xmlReader.getFeature(XMLReader::FEATURE_NAMESPACES);
136}
137
138
139inline void DOMBuilder::appendNode(AbstractNode* pNode)
140{
141 if (_pPrevious && _pPrevious != _pParent)
142 {
143 _pPrevious->_pNext = pNode;
144 pNode->_pParent = _pParent;
145 pNode->duplicate();
146 }
147 else _pParent->appendChild(pNode);
148 _pPrevious = pNode;
149}
150
151
152void DOMBuilder::notationDecl(const XMLString& name, const XMLString* publicId, const XMLString* systemId)
153{
154 DocumentType* pDoctype = _pDocument->getDoctype();
155 if (pDoctype)
156 {
157 AutoPtr<Notation> pNotation = _pDocument->createNotation(name, (publicId ? *publicId : EMPTY_STRING), (systemId ? *systemId : EMPTY_STRING));
158 pDoctype->appendChild(pNotation);
159 }
160}
161
162
163void DOMBuilder::unparsedEntityDecl(const XMLString& name, const XMLString* publicId, const XMLString& systemId, const XMLString& notationName)
164{
165 DocumentType* pDoctype = _pDocument->getDoctype();
166 if (pDoctype)
167 {
168 AutoPtr<Entity> pEntity = _pDocument->createEntity(name, publicId ? *publicId : EMPTY_STRING, systemId, notationName);
169 pDoctype->appendChild(pEntity);
170 }
171}
172
173
174void DOMBuilder::setDocumentLocator(const Locator* /*loc*/)
175{
176}
177
178
179void DOMBuilder::startDocument()
180{
181}
182
183
184void DOMBuilder::endDocument()
185{
186}
187
188
189void DOMBuilder::startElement(const XMLString& uri, const XMLString& localName, const XMLString& qname, const Attributes& attributes)
190{
191 AutoPtr<Element> pElem = _namespaces ? _pDocument->createElementNS(uri, qname.empty() ? localName : qname) : _pDocument->createElement(qname);
192
193 const AttributesImpl& attrs = dynamic_cast<const AttributesImpl&>(attributes);
194 Attr* pPrevAttr = 0;
195 for (AttributesImpl::iterator it = attrs.begin(); it != attrs.end(); ++it)
196 {
197 AutoPtr<Attr> pAttr = new Attr(_pDocument, 0, it->namespaceURI, it->localName, it->qname, it->value, it->specified);
198 pPrevAttr = pElem->addAttributeNodeNP(pPrevAttr, pAttr);
199 }
200 appendNode(pElem);
201 _pParent = pElem;
202}
203
204
205void DOMBuilder::endElement(const XMLString& /*uri*/, const XMLString& /*localName*/, const XMLString& /*qname*/)
206{
207 _pPrevious = _pParent;
208 _pParent = static_cast<AbstractContainerNode*>(_pParent->parentNode());
209}
210
211
212void DOMBuilder::characters(const XMLChar ch[], int start, int length)
213{
214 if (_inCDATA)
215 {
216 if (_pPrevious && _pPrevious->nodeType() == Node::CDATA_SECTION_NODE)
217 {
218 static_cast<CDATASection*>(_pPrevious)->appendData(XMLString(ch + start, length));
219 }
220 else
221 {
222 AutoPtr<CDATASection> pCDATA = _pDocument->createCDATASection(XMLString(ch + start, length));
223 appendNode(pCDATA);
224 }
225 }
226 else
227 {
228 if (_pPrevious && _pPrevious->nodeType() == Node::TEXT_NODE)
229 {
230 static_cast<Text*>(_pPrevious)->appendData(XMLString(ch + start, length));
231 }
232 else
233 {
234 AutoPtr<Text> pText = _pDocument->createTextNode(XMLString(ch + start, length));
235 appendNode(pText);
236 }
237 }
238}
239
240
241void DOMBuilder::ignorableWhitespace(const XMLChar ch[], int start, int length)
242{
243 characters(ch, start, length);
244}
245
246
247void DOMBuilder::processingInstruction(const XMLString& target, const XMLString& data)
248{
249 AutoPtr<ProcessingInstruction> pPI = _pDocument->createProcessingInstruction(target, data);
250 appendNode(pPI);
251}
252
253
254void DOMBuilder::startPrefixMapping(const XMLString& /*prefix*/, const XMLString& /*uri*/)
255{
256}
257
258
259void DOMBuilder::endPrefixMapping(const XMLString& /*prefix*/)
260{
261}
262
263
264void DOMBuilder::skippedEntity(const XMLString& name)
265{
266 AutoPtr<EntityReference> pER = _pDocument->createEntityReference(name);
267 appendNode(pER);
268}
269
270
271void DOMBuilder::startDTD(const XMLString& name, const XMLString& publicId, const XMLString& systemId)
272{
273 AutoPtr<DocumentType> pDoctype = new DocumentType(_pDocument, name, publicId, systemId);
274 _pDocument->setDoctype(pDoctype);
275}
276
277
278void DOMBuilder::endDTD()
279{
280}
281
282
283void DOMBuilder::startEntity(const XMLString& /*name*/)
284{
285}
286
287
288void DOMBuilder::endEntity(const XMLString& /*name*/)
289{
290}
291
292
293void DOMBuilder::startCDATA()
294{
295 _inCDATA = true;
296}
297
298
299void DOMBuilder::endCDATA()
300{
301 _inCDATA = false;
302}
303
304
305void DOMBuilder::comment(const XMLChar ch[], int start, int length)
306{
307 AutoPtr<Comment> pComment = _pDocument->createComment(XMLString(ch + start, length));
308 appendNode(pComment);
309}
310
311
312} } // namespace Poco::XML
313