| 1 | // |
| 2 | // DOMSerializer.cpp |
| 3 | // |
| 4 | // Library: XML |
| 5 | // Package: DOM |
| 6 | // Module: DOMSerializer |
| 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/DOMSerializer.h" |
| 16 | #include "Poco/DOM/Document.h" |
| 17 | #include "Poco/DOM/DocumentType.h" |
| 18 | #include "Poco/DOM/DocumentFragment.h" |
| 19 | #include "Poco/DOM/Element.h" |
| 20 | #include "Poco/DOM/Attr.h" |
| 21 | #include "Poco/DOM/Text.h" |
| 22 | #include "Poco/DOM/CDATASection.h" |
| 23 | #include "Poco/DOM/Comment.h" |
| 24 | #include "Poco/DOM/ProcessingInstruction.h" |
| 25 | #include "Poco/DOM/Entity.h" |
| 26 | #include "Poco/DOM/Notation.h" |
| 27 | #include "Poco/DOM/NamedNodeMap.h" |
| 28 | #include "Poco/DOM/AutoPtr.h" |
| 29 | #include "Poco/SAX/EntityResolver.h" |
| 30 | #include "Poco/SAX/DTDHandler.h" |
| 31 | #include "Poco/SAX/ContentHandler.h" |
| 32 | #include "Poco/SAX/LexicalHandler.h" |
| 33 | #include "Poco/SAX/AttributesImpl.h" |
| 34 | #include "Poco/SAX/ErrorHandler.h" |
| 35 | #include "Poco/SAX/SAXException.h" |
| 36 | |
| 37 | |
| 38 | namespace Poco { |
| 39 | namespace XML { |
| 40 | |
| 41 | |
| 42 | const XMLString DOMSerializer::CDATA = toXMLString("CDATA" ); |
| 43 | |
| 44 | |
| 45 | DOMSerializer::DOMSerializer(): |
| 46 | _pEntityResolver(0), |
| 47 | _pDTDHandler(0), |
| 48 | _pContentHandler(0), |
| 49 | _pErrorHandler(0), |
| 50 | _pDeclHandler(0), |
| 51 | _pLexicalHandler(0) |
| 52 | { |
| 53 | } |
| 54 | |
| 55 | |
| 56 | DOMSerializer::~DOMSerializer() |
| 57 | { |
| 58 | } |
| 59 | |
| 60 | |
| 61 | void DOMSerializer::setEntityResolver(EntityResolver* pEntityResolver) |
| 62 | { |
| 63 | _pEntityResolver = pEntityResolver; |
| 64 | } |
| 65 | |
| 66 | |
| 67 | EntityResolver* DOMSerializer::getEntityResolver() const |
| 68 | { |
| 69 | return _pEntityResolver; |
| 70 | } |
| 71 | |
| 72 | |
| 73 | void DOMSerializer::setDTDHandler(DTDHandler* pDTDHandler) |
| 74 | { |
| 75 | _pDTDHandler = pDTDHandler; |
| 76 | } |
| 77 | |
| 78 | |
| 79 | DTDHandler* DOMSerializer::getDTDHandler() const |
| 80 | { |
| 81 | return _pDTDHandler; |
| 82 | } |
| 83 | |
| 84 | |
| 85 | void DOMSerializer::setContentHandler(ContentHandler* pContentHandler) |
| 86 | { |
| 87 | _pContentHandler = pContentHandler; |
| 88 | } |
| 89 | |
| 90 | |
| 91 | ContentHandler* DOMSerializer::getContentHandler() const |
| 92 | { |
| 93 | return _pContentHandler; |
| 94 | } |
| 95 | |
| 96 | |
| 97 | void DOMSerializer::setErrorHandler(ErrorHandler* pErrorHandler) |
| 98 | { |
| 99 | _pErrorHandler = pErrorHandler; |
| 100 | } |
| 101 | |
| 102 | |
| 103 | ErrorHandler* DOMSerializer::getErrorHandler() const |
| 104 | { |
| 105 | return _pErrorHandler; |
| 106 | } |
| 107 | |
| 108 | |
| 109 | void DOMSerializer::setFeature(const XMLString& featureId, bool /*state*/) |
| 110 | { |
| 111 | if (featureId == XMLReader::FEATURE_NAMESPACES) |
| 112 | throw SAXNotSupportedException(fromXMLString(XMLReader::FEATURE_NAMESPACES)); |
| 113 | else if (featureId == XMLReader::FEATURE_NAMESPACE_PREFIXES) |
| 114 | throw SAXNotSupportedException(fromXMLString(XMLReader::FEATURE_NAMESPACE_PREFIXES)); |
| 115 | else |
| 116 | throw SAXNotRecognizedException(fromXMLString(featureId)); |
| 117 | } |
| 118 | |
| 119 | |
| 120 | bool DOMSerializer::getFeature(const XMLString& featureId) const |
| 121 | { |
| 122 | if (featureId == XMLReader::FEATURE_NAMESPACES) |
| 123 | throw SAXNotSupportedException(fromXMLString(XMLReader::FEATURE_NAMESPACES)); |
| 124 | else if (featureId == XMLReader::FEATURE_NAMESPACE_PREFIXES) |
| 125 | throw SAXNotSupportedException(fromXMLString(XMLReader::FEATURE_NAMESPACE_PREFIXES)); |
| 126 | else |
| 127 | throw SAXNotRecognizedException(fromXMLString(featureId)); |
| 128 | } |
| 129 | |
| 130 | |
| 131 | void DOMSerializer::setProperty(const XMLString& propertyId, const XMLString& /*value*/) |
| 132 | { |
| 133 | if (propertyId == XMLReader::PROPERTY_DECLARATION_HANDLER || propertyId == XMLReader::PROPERTY_LEXICAL_HANDLER) |
| 134 | throw SAXNotSupportedException(std::string("property does not take a string value: " ) + fromXMLString(propertyId)); |
| 135 | else |
| 136 | throw SAXNotRecognizedException(fromXMLString(propertyId)); |
| 137 | } |
| 138 | |
| 139 | |
| 140 | void DOMSerializer::setProperty(const XMLString& propertyId, void* value) |
| 141 | { |
| 142 | if (propertyId == XMLReader::PROPERTY_DECLARATION_HANDLER) |
| 143 | _pDeclHandler = reinterpret_cast<DeclHandler*>(value); |
| 144 | else if (propertyId == XMLReader::PROPERTY_LEXICAL_HANDLER) |
| 145 | _pLexicalHandler = reinterpret_cast<LexicalHandler*>(value); |
| 146 | else throw SAXNotRecognizedException(fromXMLString(propertyId)); |
| 147 | } |
| 148 | |
| 149 | |
| 150 | void* DOMSerializer::getProperty(const XMLString& propertyId) const |
| 151 | { |
| 152 | if (propertyId == XMLReader::PROPERTY_DECLARATION_HANDLER) |
| 153 | return _pDeclHandler; |
| 154 | else if (propertyId == XMLReader::PROPERTY_LEXICAL_HANDLER) |
| 155 | return _pLexicalHandler; |
| 156 | else throw SAXNotSupportedException(fromXMLString(propertyId)); |
| 157 | } |
| 158 | |
| 159 | |
| 160 | void DOMSerializer::serialize(const Node* pNode) |
| 161 | { |
| 162 | poco_check_ptr (pNode); |
| 163 | |
| 164 | handleNode(pNode); |
| 165 | } |
| 166 | |
| 167 | |
| 168 | void DOMSerializer::parse(InputSource* /*pSource*/) |
| 169 | { |
| 170 | throw XMLException("The DOMSerializer cannot parse an InputSource" ); |
| 171 | } |
| 172 | |
| 173 | |
| 174 | void DOMSerializer::parse(const XMLString& /*systemId*/) |
| 175 | { |
| 176 | throw XMLException("The DOMSerializer cannot parse from a system identifier" ); |
| 177 | } |
| 178 | |
| 179 | |
| 180 | void DOMSerializer::parseMemoryNP(const char* /*xml*/, std::size_t /*size*/) |
| 181 | { |
| 182 | throw XMLException("The DOMSerializer cannot parse from memory" ); |
| 183 | } |
| 184 | |
| 185 | |
| 186 | void DOMSerializer::iterate(const Node* pNode) const |
| 187 | { |
| 188 | while (pNode) |
| 189 | { |
| 190 | handleNode(pNode); |
| 191 | pNode = pNode->nextSibling(); |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | |
| 196 | void DOMSerializer::handleNode(const Node* pNode) const |
| 197 | { |
| 198 | switch (pNode->nodeType()) |
| 199 | { |
| 200 | case Node::ELEMENT_NODE: |
| 201 | handleElement(static_cast<const Element*>(pNode)); |
| 202 | break; |
| 203 | case Node::TEXT_NODE: |
| 204 | handleCharacterData(static_cast<const Text*>(pNode)); |
| 205 | break; |
| 206 | case Node::CDATA_SECTION_NODE: |
| 207 | handleCDATASection(static_cast<const CDATASection*>(pNode)); |
| 208 | break; |
| 209 | case Node::ENTITY_NODE: |
| 210 | handleEntity(static_cast<const Entity*>(pNode)); |
| 211 | break; |
| 212 | case Node::PROCESSING_INSTRUCTION_NODE: |
| 213 | handlePI(static_cast<const ProcessingInstruction*>(pNode)); |
| 214 | break; |
| 215 | case Node::COMMENT_NODE: |
| 216 | handleComment(static_cast<const Comment*>(pNode)); |
| 217 | break; |
| 218 | case Node::DOCUMENT_NODE: |
| 219 | handleDocument(static_cast<const Document*>(pNode)); |
| 220 | break; |
| 221 | case Node::DOCUMENT_TYPE_NODE: |
| 222 | handleDocumentType(static_cast<const DocumentType*>(pNode)); |
| 223 | break; |
| 224 | case Node::DOCUMENT_FRAGMENT_NODE: |
| 225 | handleFragment(static_cast<const DocumentFragment*>(pNode)); |
| 226 | break; |
| 227 | case Node::NOTATION_NODE: |
| 228 | handleNotation(static_cast<const Notation*>(pNode)); |
| 229 | break; |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | |
| 234 | void DOMSerializer::handleElement(const Element* pElement) const |
| 235 | { |
| 236 | if (_pContentHandler) |
| 237 | { |
| 238 | AutoPtr<NamedNodeMap> pAttrs = pElement->attributes(); |
| 239 | AttributesImpl saxAttrs; |
| 240 | for (unsigned long i = 0; i < pAttrs->length(); ++i) |
| 241 | { |
| 242 | Attr* pAttr = static_cast<Attr*>(pAttrs->item(i)); |
| 243 | saxAttrs.addAttribute(pAttr->namespaceURI(), pAttr->localName(), pAttr->nodeName(), CDATA, pAttr->value(), pAttr->specified()); |
| 244 | } |
| 245 | _pContentHandler->startElement(pElement->namespaceURI(), pElement->localName(), pElement->tagName(), saxAttrs); |
| 246 | } |
| 247 | iterate(pElement->firstChild()); |
| 248 | if (_pContentHandler) |
| 249 | _pContentHandler->endElement(pElement->namespaceURI(), pElement->localName(), pElement->tagName()); |
| 250 | } |
| 251 | |
| 252 | |
| 253 | void DOMSerializer::handleCharacterData(const Text* pText) const |
| 254 | { |
| 255 | if (_pContentHandler) |
| 256 | { |
| 257 | const XMLString& data = pText->data(); |
| 258 | _pContentHandler->characters(data.c_str(), 0, (int) data.length()); |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | |
| 263 | void DOMSerializer::handleComment(const Comment* ) const |
| 264 | { |
| 265 | if (_pLexicalHandler) |
| 266 | { |
| 267 | const XMLString& data = pComment->data(); |
| 268 | _pLexicalHandler->comment(data.c_str(), 0, (int) data.length()); |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | |
| 273 | void DOMSerializer::handlePI(const ProcessingInstruction* pPI) const |
| 274 | { |
| 275 | if (_pContentHandler) _pContentHandler->processingInstruction(pPI->target(), pPI->data()); |
| 276 | } |
| 277 | |
| 278 | |
| 279 | void DOMSerializer::handleCDATASection(const CDATASection* pCDATA) const |
| 280 | { |
| 281 | if (_pLexicalHandler) _pLexicalHandler->startCDATA(); |
| 282 | handleCharacterData(pCDATA); |
| 283 | if (_pLexicalHandler) _pLexicalHandler->endCDATA(); |
| 284 | } |
| 285 | |
| 286 | |
| 287 | void DOMSerializer::handleDocument(const Document* pDocument) const |
| 288 | { |
| 289 | if (_pContentHandler) _pContentHandler->startDocument(); |
| 290 | const DocumentType* pDoctype = pDocument->doctype(); |
| 291 | if (pDoctype) handleDocumentType(pDoctype); |
| 292 | iterate(pDocument->firstChild()); |
| 293 | if (_pContentHandler) _pContentHandler->endDocument(); |
| 294 | } |
| 295 | |
| 296 | |
| 297 | void DOMSerializer::handleDocumentType(const DocumentType* pDocumentType) const |
| 298 | { |
| 299 | if (_pLexicalHandler) _pLexicalHandler->startDTD(pDocumentType->name(), pDocumentType->publicId(), pDocumentType->systemId()); |
| 300 | iterate(pDocumentType->firstChild()); |
| 301 | if (_pLexicalHandler) _pLexicalHandler->endDTD(); |
| 302 | } |
| 303 | |
| 304 | |
| 305 | void DOMSerializer::handleFragment(const DocumentFragment* pFragment) const |
| 306 | { |
| 307 | iterate(pFragment->firstChild()); |
| 308 | } |
| 309 | |
| 310 | |
| 311 | void DOMSerializer::handleNotation(const Notation* pNotation) const |
| 312 | { |
| 313 | if (_pDTDHandler) _pDTDHandler->notationDecl(pNotation->nodeName(), &pNotation->publicId(), &pNotation->systemId()); |
| 314 | } |
| 315 | |
| 316 | |
| 317 | void DOMSerializer::handleEntity(const Entity* pEntity) const |
| 318 | { |
| 319 | if (_pDTDHandler) _pDTDHandler->unparsedEntityDecl(pEntity->nodeName(), &pEntity->publicId(), pEntity->systemId(), pEntity->notationName()); |
| 320 | } |
| 321 | |
| 322 | |
| 323 | } } // namespace Poco::XML |
| 324 | |