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