From 5e527213a2430bb3018e5eebd909aef294edf9b5 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 18 Dec 2020 18:48:46 +0300 Subject: Switch to build2 --- xsd-examples/cxx/tree/streaming/serializer.cxx | 636 +++++++++++++++++++++++++ 1 file changed, 636 insertions(+) create mode 100644 xsd-examples/cxx/tree/streaming/serializer.cxx (limited to 'xsd-examples/cxx/tree/streaming/serializer.cxx') diff --git a/xsd-examples/cxx/tree/streaming/serializer.cxx b/xsd-examples/cxx/tree/streaming/serializer.cxx new file mode 100644 index 0000000..b903a49 --- /dev/null +++ b/xsd-examples/cxx/tree/streaming/serializer.cxx @@ -0,0 +1,636 @@ +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "serializer.hxx" + +using namespace std; +using namespace xercesc; + +namespace xml = xsd::cxx::xml; +namespace tree = xsd::cxx::tree; + +static const XMLCh gEOLSeq[] = +{ + chLF, chNull +}; + +static const XMLCh gUTF8[] = +{ + chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull +}; + +static const XMLCh gEndElement[] = +{ + chOpenAngle, chForwardSlash, chNull +}; + +static const int DISCARD_DEFAULT_CONTENT_ID = 0x1; +static const int ENTITIES_ID = 0x2; +static const int FORMAT_PRETTY_PRINT_1ST_LEVEL_ID = 0xA; + +class StreamingDOMSerializer: public DOMLSSerializerImpl +{ +public: + StreamingDOMSerializer (MemoryManager* manager) + : DOMLSSerializerImpl (manager) + { + } + + bool + startOpen (const DOMElement* e, DOMLSOutput* const destination) + { + const DOMDocument* docu (e->getOwnerDocument ()); + assert (docu != 0); + + // Code adapted from DOMLSSerializerImpl::write(). + // + target_ = destination->getByteStream(); + + fEncodingUsed = gUTF8; + + const XMLCh* lsEncoding=destination->getEncoding(); + if (lsEncoding && *lsEncoding) + { + fEncodingUsed = lsEncoding; + } + else if (docu) + { + const XMLCh* tmpEncoding = docu->getInputEncoding(); + + if ( tmpEncoding && *tmpEncoding) + { + fEncodingUsed = tmpEncoding; + } + else + { + tmpEncoding = docu->getXmlEncoding(); + + if ( tmpEncoding && *tmpEncoding) + { + fEncodingUsed = tmpEncoding; + } + } + } + + fNewLineUsed = (fNewLine && *fNewLine)? fNewLine : gEOLSeq; + + fDocumentVersion = (docu->getXmlVersion() && *(docu->getXmlVersion())) + ? docu->getXmlVersion() + : XMLUni::fgVersion1_0; + + fErrorCount = 0; + + fLineFeedInTextNodePrinted = false; + fLastWhiteSpaceInTextNode = 0; + + level_ = 0; + namespace_map_.clear (); + + fFormatter = new (fMemoryManager) XMLFormatter( fEncodingUsed + ,fDocumentVersion + ,target_ + ,XMLFormatter::NoEscapes + ,XMLFormatter::UnRep_CharRef + ,fMemoryManager); + formatter_.reset (fFormatter); + + // Write out the XML declaration, etc. Here we assume that the document + // has no children (i.e., no root element). + // + processNode (docu, 0); + fLineFeedInTextNodePrinted = true; + + return writeOpen (e); + } + + bool + writeOpen (const DOMElement* e) + { + // Code adapted from the first part of ELEMENT_NODE case in + // DOMLSSerializerImpl::processNode(). + // + + if (!fLineFeedInTextNodePrinted) + { + if(level_ == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID)) + printNewLine(); + + printNewLine(); + } + else + { + fLineFeedInTextNodePrinted = false; + } + + printIndent(level_); + + RefHashTableOf* namespaceMap = NULL; + + *fFormatter << XMLFormatter::NoEscapes << chOpenAngle << + e->getNodeName (); + + setURCharRef(); + DOMNamedNodeMap *attributes = e->getAttributes(); + XMLSize_t attrCount = attributes->getLength(); + + const XMLCh* prefix = e->getPrefix(); + const XMLCh* uri = e->getNamespaceURI(); + if((uri && uri[0]) || + ((prefix==0 || prefix[0]==0) && isDefaultNamespacePrefixDeclared())) + { + if(prefix==0 || prefix[0]==0) + prefix=XMLUni::fgZeroLenString; + if(!isNamespaceBindingActive(prefix, uri)) + { + if(namespaceMap==NULL) + { + namespaceMap=new (fMemoryManager) RefHashTableOf(12, false, fMemoryManager); + fNamespaceStack->addElement(namespaceMap); + } + namespaceMap->put((void*)prefix,(XMLCh*)uri); + *fFormatter << XMLFormatter::NoEscapes + << chSpace << XMLUni::fgXMLNSString; + + if(!XMLString::equals(prefix,XMLUni::fgZeroLenString)) + *fFormatter << chColon << prefix; + + *fFormatter << chEqual << chDoubleQuote + << XMLFormatter::AttrEscapes + << uri + << XMLFormatter::NoEscapes + << chDoubleQuote; + } + } + + bool discard = getFeature(DISCARD_DEFAULT_CONTENT_ID); + for (XMLSize_t i = 0; i < attrCount; i++) + { + DOMAttr* attribute = (DOMAttr*)attributes->item(i); + + if (discard && !((DOMAttr*)attribute )->getSpecified()) + continue; + + // if this attribute is a namespace declaration, add it to the namespace map for the current level + const XMLCh* ns = attribute->getNamespaceURI(); + if (ns != 0 ) + { + if(XMLString::equals(ns, XMLUni::fgXMLNSURIName)) + { + if(namespaceMap==NULL) + { + namespaceMap=new (fMemoryManager) RefHashTableOf(12, false, fMemoryManager); + fNamespaceStack->addElement(namespaceMap); + } + const XMLCh* nsPrefix = attribute->getLocalName(); + if(XMLString::equals(attribute->getNodeName(),XMLUni::fgXMLNSString)) + nsPrefix = XMLUni::fgZeroLenString; + if(namespaceMap->containsKey((void*)nsPrefix)) + continue; + namespaceMap->put((void*)attribute->getLocalName(),(XMLCh*)attribute->getNodeValue()); + } + else if(!XMLString::equals(ns, XMLUni::fgXMLURIName)) + { + // check if the namespace for the current node is already defined + const XMLCh* prefix = attribute->getPrefix(); + if(prefix && prefix[0]) + { + const XMLCh* uri = attribute->getNamespaceURI(); + if(!isNamespaceBindingActive(prefix, uri)) + { + if(namespaceMap==NULL) + { + namespaceMap=new (fMemoryManager) RefHashTableOf(12, false, fMemoryManager); + fNamespaceStack->addElement(namespaceMap); + } + namespaceMap->put((void*)prefix,(XMLCh*)uri); + + *fFormatter << XMLFormatter::NoEscapes + << chSpace << XMLUni::fgXMLNSString << chColon << prefix + << chEqual << chDoubleQuote + << XMLFormatter::AttrEscapes + << uri + << XMLFormatter::NoEscapes + << chDoubleQuote; + } + } + } + } + + if (XMLString::equals(ns, XMLUni::fgXMLNSURIName) || checkFilter(attribute) == DOMNodeFilter::FILTER_ACCEPT) + { + *fFormatter << XMLFormatter::NoEscapes + << chSpace << attribute->getNodeName() + << chEqual << chDoubleQuote + << XMLFormatter::AttrEscapes; + + if (getFeature(ENTITIES_ID)) + { + DOMNode* child = attribute->getFirstChild(); + while( child != 0) + { + if(child->getNodeType()==DOMNode::TEXT_NODE) + *fFormatter << child->getNodeValue(); + else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE) + *fFormatter << XMLFormatter::NoEscapes + << chAmpersand << child->getNodeName() << chSemiColon + << XMLFormatter::AttrEscapes; + child = child->getNextSibling(); + } + } + else + *fFormatter << attribute->getNodeValue(); + + *fFormatter << XMLFormatter::NoEscapes << chDoubleQuote; + } + } + + *fFormatter << XMLFormatter::NoEscapes << chCloseAngle; + + // Keep track of whether we have added a namespace map for this + // element. Used to pop it in writeClose(). + // + namespace_map_.push_back (namespaceMap != 0); + + level_++; + + DOMNode* child = e->getFirstChild(); + while (child != 0) + { + processNode (child, level_); + child = child->getNextSibling(); + } + + return fErrorCount == 0; + } + + bool + writeClose (const XMLCh* name) + { + // Code adapted from the second part of ELEMENT_NODE case in + // DOMLSSerializerImpl::processNode(). + // + level_--; + + // Assume we are not on the same line (nodeLine != fCurrentLine). + // + { + if (!fLineFeedInTextNodePrinted) + { + printNewLine(); + } + else + { + fLineFeedInTextNodePrinted = false; + } + + if(level_ == 0 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID)) + printNewLine(); + + printIndent(level_); + } + + *fFormatter << XMLFormatter::NoEscapes << gEndElement << + name << chCloseAngle; + + if (namespace_map_.back ()) + fNamespaceStack->removeLastElement(); + + namespace_map_.pop_back (); + + if (level_ == 0) + { + printNewLine(); + target_->flush (); + } + + return fErrorCount == 0; + } + + bool + write (const DOMElement* e) + { + processNode (e, level_); + return fErrorCount == 0; + } + + using DOMLSSerializerImpl::write; // Whole document. + +public: + // Update the namespace stack to point to the strings from the + // new document's string pool. + // + void + update_namespace_stack (DOMDocument& d) + { + DOMDocumentImpl& di (dynamic_cast (d)); + + for (XMLSize_t i (0); i != fNamespaceStack->size (); ++i) + { + RefHashTableOf& t (*fNamespaceStack->elementAt (i)); + RefHashTableOfEnumerator e (&t, false, fMemoryManager); + while (e.hasMoreElements ()) + { + XMLCh* k ((XMLCh*) (e.nextElementKey ())); + XMLCh* v (t.get (k)); + t.put ((void*) (di.getPooledString (k)), + (XMLCh*) (di.getPooledString (v))); + } + } + } + +private: + XMLFormatTarget* target_; + std::unique_ptr formatter_; + int level_; + + std::vector namespace_map_; +}; + +class serializer_impl +{ +public: + typedef serializer::namespace_infomap namespace_infomap; + + serializer_impl (); + + void + start (ostream& os, const string& encoding); + + DOMElement* + create (const string& name, const namespace_infomap&); + + DOMElement* + create (const string& ns, const string& qname, const namespace_infomap&); + + void + serialize (xml::dom::unique_ptr); + + void + serialize_open (xml::dom::unique_ptr); + + void + serialize_close (const string&); + +private: + void + clear_document (); + +private: + bool start_; + + // Serializer. + // + xml::dom::unique_ptr out_; + xml::dom::unique_ptr serializer_; + + unique_ptr oft_; + + tree::error_handler error_handler_; + xml::dom::bits::error_handler_proxy error_proxy_; + + // DOM document that we use to create the elements. + // + DOMImplementation& dom_impl_; + xml::dom::unique_ptr doc_; + vector element_stack_; + + size_t element_count_; // Number of elements serialized using current doc. + static const size_t element_count_limit_ = 500; +}; + +const XMLCh ls[] = {chLatin_L, chLatin_S, chNull}; + +serializer_impl:: +serializer_impl () + : error_proxy_ (error_handler_), + dom_impl_ (*DOMImplementationRegistry::getDOMImplementation (ls)) +{ + serializer_.reset ( + new (XMLPlatformUtils::fgMemoryManager) + StreamingDOMSerializer (XMLPlatformUtils::fgMemoryManager)); + + DOMConfiguration* conf (serializer_->getDomConfig ()); + conf->setParameter (XMLUni::fgDOMErrorHandler, &error_proxy_); + conf->setParameter (XMLUni::fgDOMXMLDeclaration, true); + conf->setParameter (XMLUni::fgDOMWRTDiscardDefaultContent, true); + conf->setParameter (XMLUni::fgDOMWRTFormatPrettyPrint, true); + conf->setParameter (XMLUni::fgDOMWRTXercesPrettyPrint, false); +} + +void serializer_impl:: +start (ostream& os, const string& encoding) +{ + element_stack_.clear (); + doc_.reset (dom_impl_.createDocument ()); + element_count_ = 0; + + error_handler_.reset (); + oft_.reset (new xml::dom::ostream_format_target (os)); + + out_.reset (dom_impl_.createLSOutput ()); + out_->setEncoding (xml::string (encoding).c_str ()); + out_->setByteStream (oft_.get ()); + + start_ = true; +} + +DOMElement* serializer_impl:: +create (const string& name, const namespace_infomap& map) +{ + DOMElement* r (doc_->createElement (xml::string (name).c_str ())); + + if (!map.empty ()) + xml::dom::add_namespaces (*r, map); + + // Add the element as the child of the stack "tip" so that it + // "sees" all the namespace declarations active from this point. + // + if (!element_stack_.empty ()) + element_stack_.back ()->appendChild (r); + + return r; +} + +DOMElement* serializer_impl:: +create (const string& ns, const string& qname, const namespace_infomap& map) +{ + DOMElement* r ( + doc_->createElementNS ( + xml::string (ns).c_str (), xml::string (qname).c_str ())); + + if (!map.empty ()) + xml::dom::add_namespaces (*r, map); + + // Add the element as the child of the stack "tip" so that it + // "sees" all the namespace declarations active from this point. + // + if (!element_stack_.empty ()) + element_stack_.back ()->appendChild (r); + + return r; +} + +void serializer_impl:: +serialize (xml::dom::unique_ptr p) +{ + DOMElement* e (p.get ()); + + if (start_) + { + serializer_->write (e, out_.get ()); + start_ = false; + } + else + serializer_->write (e); + + error_handler_.throw_if_failed > (); + + // Remove this element from its parent before we release. + // + if (!element_stack_.empty ()) + element_stack_.back ()->removeChild (e); + + p.reset (); // Release it before we may clear the document below. + + if (element_count_++ > element_count_limit_) + clear_document (); +} + +void serializer_impl:: +serialize_open (xml::dom::unique_ptr p) +{ + DOMElement* e (p.get ()); + + if (start_) + { + serializer_->startOpen (e, out_.get ()); + start_ = false; + } + else + serializer_->writeOpen (e); + + error_handler_.throw_if_failed > (); + + // Add this element to the element stack. serialize_close() is + // responsible for its removal and releasing. + // + element_stack_.push_back (e); + p.release (); +} + +void serializer_impl:: +serialize_close (const string& name) +{ + serializer_->writeClose (xml::string (name).c_str ()); + error_handler_.throw_if_failed > (); + + // Release the element. + // + DOMElement* e (element_stack_.back ()); + element_stack_.pop_back (); + + if (!element_stack_.empty ()) + element_stack_.back ()->removeChild (e); + + e->release (); + + if (element_count_++ > element_count_limit_) + clear_document (); +} + +void serializer_impl:: +clear_document () +{ + // Re-create the document in order to force deallocation of its + // internal heap. While Xerces-C++ DOM tries to re-use memory, + // it still accumulates no longer used memory blocks. + // + xml::dom::unique_ptr doc (dom_impl_.createDocument ()); + + if (!element_stack_.empty ()) + { + DOMElement* e ( + static_cast ( + doc->importNode (element_stack_.front (), true))); + + for (vector::iterator i (element_stack_.begin ()); + i != element_stack_.end (); + ++i) + { + *i = e; + e = static_cast (e->getFirstChild ()); + } + } + + // Update the namespace stack to use the new document. + // + serializer_->update_namespace_stack (*doc); + + doc_ = move (doc); + element_count_ = 0; +} + +// +// serializer +// + +serializer:: +~serializer () +{ +} + +serializer:: +serializer () + : impl_ (new serializer_impl) +{ +} + +void serializer:: +start (ostream& os, const string& encoding) +{ + impl_->start (os, encoding); +} + +DOMElement* serializer:: +create (const string& name, const namespace_infomap& map) +{ + return impl_->create (name, map); +} + +DOMElement* serializer:: +create (const string& ns, const string& qname, const namespace_infomap& map) +{ + return impl_->create (ns, qname, map); +} + +void serializer:: +serialize (xml::dom::unique_ptr e) +{ + impl_->serialize (move (e)); +} + +void serializer:: +serialize_open (xml::dom::unique_ptr e) +{ + impl_->serialize_open (move (e)); +} + +void serializer:: +serialize_close (const string& name) +{ + impl_->serialize_close (name); +} -- cgit v1.1