GME  13
DOMLSSerializerImpl.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: DOMLSSerializerImpl.cpp 768978 2009-04-27 13:45:52Z amassari $
00020  */
00021 
00022 #include "DOMLSSerializerImpl.hpp"
00023 #include "DOMLSOutputImpl.hpp"
00024 #include "DOMErrorImpl.hpp"
00025 #include "DOMLocatorImpl.hpp"
00026 #include "DOMImplementationImpl.hpp"
00027 #include "DOMStringListImpl.hpp"
00028 
00029 #include <xercesc/framework/MemBufFormatTarget.hpp>
00030 #include <xercesc/framework/LocalFileFormatTarget.hpp>
00031 
00032 #include <xercesc/util/TransService.hpp>
00033 #include <xercesc/util/TranscodingException.hpp>
00034 #include <xercesc/util/Janitor.hpp>
00035 #include <xercesc/util/XMLString.hpp>
00036 #include <xercesc/util/XMLUniDefs.hpp>
00037 #include <xercesc/util/XMLMsgLoader.hpp>
00038 #include <xercesc/dom/StDOMNode.hpp>
00039 #include <xercesc/util/OutOfMemoryException.hpp>
00040 #include <xercesc/util/XMLChar.hpp>
00041 
00042 XERCES_CPP_NAMESPACE_BEGIN
00043 
00044 
00045 // ---------------------------------------------------------------------------
00046 //  Local const data
00047 //
00048 // ---------------------------------------------------------------------------
00049 
00050 static const int INVALID_FEATURE_ID               = -1;
00051 static const int CANONICAL_FORM_ID                = 0x0;
00052 static const int DISCARD_DEFAULT_CONTENT_ID       = 0x1;
00053 static const int ENTITIES_ID                      = 0x2;
00054 static const int FORMAT_PRETTY_PRINT_ID           = 0x3;
00055 static const int NORMALIZE_CHARACTERS_ID          = 0x4;
00056 static const int SPLIT_CDATA_SECTIONS_ID          = 0x5;
00057 static const int VALIDATION_ID                    = 0x6;
00058 static const int WHITESPACE_IN_ELEMENT_CONTENT_ID = 0x7;
00059 static const int BYTE_ORDER_MARK_ID               = 0x8;
00060 static const int XML_DECLARATION                  = 0x9;
00061 static const int FORMAT_PRETTY_PRINT_1ST_LEVEL_ID = 0xA;
00062 
00063 //    feature                      true                       false
00064 // ================================================================================
00065 //canonical-form                 [optional] Not Supported     [required] (default)
00066 //discard-default-content        [required] (default)         [required]
00067 //entity                         [required] (default)         [optional]
00068 //format-pretty-print            [optional] Partially Supported [required] (default)
00069 //normalize-characters           [optional] Not Supported     [required] (default)
00070 //split-cdata-sections           [required] (default)         [required]
00071 //validation                     [optional] Not Supported     [required] (default)
00072 //whitespace-in-element-content  [requierd] (default)         [optional] Not Supported
00073 //
00074 
00075 //
00076 // Each feature has 2 entries in this array,
00077 // the first for "true",
00078 // the second for "false".
00079 //
00080 static const bool  featuresSupported[] = {
00081     false, true,  // canonical-form
00082     true,  true,  // discard-default-content
00083     true,  true,  // entity
00084     true,  true,  // format-pretty-print
00085     false, true,  // normalize-characters
00086     true,  true,  // split-cdata-sections
00087     false, true,  // validation
00088     true,  false, // whitespace-in-element-content
00089     true,  true,  // http://apache.org/xml/features/dom/byte-order-mark
00090     true,  true,  // xml-declaration
00091     true,  true   // http://apache.org/xml/features/pretty-print/space-first-level-elements
00092 };
00093 
00094 // default end-of-line sequence
00095 static const XMLCh  gEOLSeq[] =
00096 {
00097     chLF, chNull
00098 };
00099 
00100 //UTF-8
00101 static const XMLCh  gUTF8[] =
00102 {
00103     chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull
00104 };
00105 
00106 //</
00107 static const XMLCh  gEndElement[] =
00108 {
00109     chOpenAngle, chForwardSlash, chNull
00110 };
00111 
00112 //?>
00113 static const XMLCh  gEndPI[] =
00114 {
00115     chQuestion, chCloseAngle, chNull
00116 };
00117 
00118 //<?
00119 static const XMLCh  gStartPI[] =
00120 {
00121     chOpenAngle, chQuestion, chNull
00122 };
00123 
00124 //<?xml version="
00125 static const XMLCh  gXMLDecl_VersionInfo[] =
00126 {
00127     chOpenAngle, chQuestion, chLatin_x,     chLatin_m,  chLatin_l,  chSpace,
00128     chLatin_v,   chLatin_e,  chLatin_r,     chLatin_s,  chLatin_i,  chLatin_o,
00129     chLatin_n,   chEqual,    chDoubleQuote, chNull
00130 };
00131 
00132 static const XMLCh gXMLDecl_ver10[] =
00133 {
00134     chDigit_1, chPeriod, chDigit_0, chNull
00135 };
00136 
00137 //encoding="
00138 static const XMLCh  gXMLDecl_EncodingDecl[] =
00139 {
00140     chLatin_e,  chLatin_n,  chLatin_c,  chLatin_o,      chLatin_d, chLatin_i,
00141     chLatin_n,  chLatin_g,  chEqual,    chDoubleQuote,  chNull
00142 };
00143 
00144 //" standalone="
00145 static const XMLCh  gXMLDecl_SDDecl[] =
00146 {
00147     chLatin_s, chLatin_t, chLatin_a,   chLatin_n,    chLatin_d,   chLatin_a,
00148     chLatin_l, chLatin_o, chLatin_n,   chLatin_e,    chEqual,     chDoubleQuote,
00149     chNull
00150 };
00151 
00152 //"
00153 static const XMLCh  gXMLDecl_separator[] =
00154 {
00155     chDoubleQuote, chSpace, chNull
00156 };
00157 
00158 //?>
00159 static const XMLCh  gXMLDecl_endtag[] =
00160 {
00161     chQuestion, chCloseAngle,  chNull
00162 };
00163 
00164 //<![CDATA[
00165 static const XMLCh  gStartCDATA[] =
00166 {
00167     chOpenAngle, chBang,    chOpenSquare, chLatin_C, chLatin_D,
00168     chLatin_A,   chLatin_T, chLatin_A,    chOpenSquare, chNull
00169 };
00170 
00171 //]]>
00172 static const XMLCh  gEndCDATA[] =
00173 {
00174 //    chCloseSquare, chCloseAngle, chCloseAngle, chNull  // test only: ]>>
00175       chCloseSquare, chCloseSquare, chCloseAngle, chNull
00176 };
00177 
00178 //<!--
00179 static const XMLCh  gStartComment[] =
00180 {
00181     chOpenAngle, chBang, chDash, chDash, chNull
00182 };
00183 
00184 //-->
00185 static const XMLCh  gEndComment[] =
00186 {
00187     chDash, chDash, chCloseAngle, chNull
00188 };
00189 
00190 //<!DOCTYPE
00191 static const XMLCh  gStartDoctype[] =
00192 {
00193     chOpenAngle, chBang,    chLatin_D, chLatin_O, chLatin_C, chLatin_T,
00194     chLatin_Y,   chLatin_P, chLatin_E, chSpace,   chNull
00195 };
00196 
00197 //PUBLIC "
00198 static const XMLCh  gPublic[] =
00199 {
00200     chLatin_P, chLatin_U, chLatin_B,     chLatin_L, chLatin_I,
00201     chLatin_C, chSpace,   chDoubleQuote, chNull
00202 };
00203 
00204 //SYSTEM "
00205 static const XMLCh  gSystem[] =
00206 {
00207     chLatin_S, chLatin_Y, chLatin_S,     chLatin_T, chLatin_E,
00208     chLatin_M, chSpace,   chDoubleQuote, chNull
00209 };
00210 
00211 //<!ENTITY
00212 static const XMLCh  gStartEntity[] =
00213 {
00214     chOpenAngle, chBang,    chLatin_E, chLatin_N, chLatin_T, chLatin_I,
00215     chLatin_T,   chLatin_Y, chSpace,   chNull
00216 };
00217 
00218 //NDATA "
00219 static const XMLCh  gNotation[] =
00220 {
00221     chLatin_N, chLatin_D,     chLatin_A, chLatin_T, chLatin_A,
00222     chSpace,   chDoubleQuote, chNull
00223 };
00224 
00225 static const XMLByte  BOM_utf8[]    = {(XMLByte)0xEF, (XMLByte)0xBB, (XMLByte)0xBF, (XMLByte) 0};
00226 static const XMLByte  BOM_utf16be[] = {(XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
00227 static const XMLByte  BOM_utf16le[] = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte) 0};
00228 static const XMLByte  BOM_ucs4be[]  = {(XMLByte)0x00, (XMLByte)0x00, (XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
00229 static const XMLByte  BOM_ucs4le[]  = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte)0x00, (XMLByte)0x00, (XMLByte) 0};
00230 
00231 //
00232 // Notification of the error though error handler
00233 //
00234 // The application may instruct the engine to abort serialization
00235 // by returning "false".
00236 //
00237 // REVISIT: update the locator ctor once the line#, col#, uri and offset
00238 // are available from DOM3 core
00239 //
00240 // REVISIT: use throwing exception to abort serialization is an interesting
00241 // thing here, since the serializer is a recusive function, we
00242 // can't use return, obviously. However we may have multiple try/catch
00243 // along its way going back to write(). So far we don't come up with a
00244 // "short-cut" to go "directly" back.
00245 //
00246 #define  TRY_CATCH_THROW(action)                                     \
00247 fFormatter->setUnRepFlags(XMLFormatter::UnRep_Fail);                 \
00248 try                                                                  \
00249 {                                                                    \
00250     action;                                                          \
00251 }                                                                    \
00252 catch(TranscodingException const &e)                                 \
00253 {                                                                    \
00254     reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());  \
00255     throw e;                                                         \
00256 }
00257 
00258 DOMLSSerializerImpl::~DOMLSSerializerImpl()
00259 {
00260     fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
00261     delete fNamespaceStack;
00262     delete fSupportedParameters;
00263     // we don't own/adopt error handler and filter
00264 }
00265 
00266 DOMLSSerializerImpl::DOMLSSerializerImpl(MemoryManager* const manager)
00267 :fFeatures(0)
00268 ,fNewLine(0)
00269 ,fErrorHandler(0)
00270 ,fFilter(0)
00271 ,fDocumentVersion(XMLUni::fgVersion1_0)
00272 ,fSupportedParameters(0)
00273 ,fEncodingUsed(0)
00274 ,fNewLineUsed(0)
00275 ,fFormatter(0)
00276 ,fErrorCount(0)
00277 ,fCurrentLine(0)
00278 ,fLineFeedInTextNodePrinted(false)
00279 ,fLastWhiteSpaceInTextNode(0)
00280 ,fNamespaceStack(0)
00281 ,fMemoryManager(manager)
00282 {
00283     fNamespaceStack=new (fMemoryManager) RefVectorOf< RefHashTableOf<XMLCh> >(0,true, fMemoryManager);
00284 
00285     //
00286     // set features to default setting
00287     //
00288     setFeature(CANONICAL_FORM_ID,                false);
00289     setFeature(DISCARD_DEFAULT_CONTENT_ID,       true );
00290     setFeature(ENTITIES_ID,                      true );
00291     setFeature(FORMAT_PRETTY_PRINT_ID,           false);
00292     setFeature(NORMALIZE_CHARACTERS_ID,          false);
00293     setFeature(SPLIT_CDATA_SECTIONS_ID,          true );
00294     setFeature(VALIDATION_ID,                    false);
00295     setFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID, true );
00296     setFeature(BYTE_ORDER_MARK_ID,               false);
00297     setFeature(XML_DECLARATION,                  true );
00298     setFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID, true );
00299 
00300     fSupportedParameters=new (fMemoryManager) DOMStringListImpl(12, fMemoryManager);
00301     fSupportedParameters->add(XMLUni::fgDOMErrorHandler);
00302     fSupportedParameters->add(XMLUni::fgDOMWRTCanonicalForm);
00303     fSupportedParameters->add(XMLUni::fgDOMWRTDiscardDefaultContent);
00304     fSupportedParameters->add(XMLUni::fgDOMWRTEntities);
00305     fSupportedParameters->add(XMLUni::fgDOMWRTFormatPrettyPrint);
00306     fSupportedParameters->add(XMLUni::fgDOMWRTNormalizeCharacters);
00307     fSupportedParameters->add(XMLUni::fgDOMWRTSplitCdataSections);
00308     fSupportedParameters->add(XMLUni::fgDOMWRTValidation);
00309     fSupportedParameters->add(XMLUni::fgDOMWRTWhitespaceInElementContent);
00310     fSupportedParameters->add(XMLUni::fgDOMWRTBOM);
00311     fSupportedParameters->add(XMLUni::fgDOMXMLDeclaration);
00312     fSupportedParameters->add(XMLUni::fgDOMWRTXercesPrettyPrint);
00313 }
00314 
00315 bool DOMLSSerializerImpl::canSetParameter(const XMLCh* featName
00316                                         , const void*  /*value*/) const
00317 {
00318     if(XMLString::compareIStringASCII(featName, XMLUni::fgDOMErrorHandler)==0)
00319         return true;
00320     return false;
00321 }
00322 
00323 bool DOMLSSerializerImpl::canSetParameter(const XMLCh* featName
00324                                         , bool         state) const
00325 {
00326     int featureId = INVALID_FEATURE_ID;
00327     return checkFeature(featName, false, featureId) ? canSetFeature(featureId, state) : false;
00328 }
00329 
00330 void DOMLSSerializerImpl::setParameter(const XMLCh* featName
00331                                      , const void*  value)
00332 {
00333     if(XMLString::compareIStringASCII(featName, XMLUni::fgDOMErrorHandler)==0)
00334         fErrorHandler = (DOMErrorHandler*)value;
00335     else
00336         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
00337 }
00338 
00339 void DOMLSSerializerImpl::setParameter(const XMLCh* featName
00340                                      , bool         state)
00341 {
00342     int featureId = INVALID_FEATURE_ID;
00343     checkFeature(featName, true, featureId);
00344 
00345     if (!canSetFeature(featureId, state))
00346         throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
00347 
00348     setFeature(featureId, state);
00349 
00350     //
00351     // setting "canonical-form" to true will set the parameters "format-pretty-print",
00352     // "discard-default-content", and "xml-declaration", to false
00353     //
00354     if ((featureId == CANONICAL_FORM_ID) && state)
00355     {
00356         setFeature(FORMAT_PRETTY_PRINT_ID, false);
00357         setFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID, false);
00358         setFeature(DISCARD_DEFAULT_CONTENT_ID, false);
00359         setFeature(XML_DECLARATION, false);
00360     }
00361     // Setting one of those parameters to true will set "canonical-form" to false.
00362     if ((featureId == FORMAT_PRETTY_PRINT_ID || featureId == DISCARD_DEFAULT_CONTENT_ID || featureId == XML_DECLARATION) && state)
00363         setFeature(CANONICAL_FORM_ID, false);
00364 }
00365 
00366 const void* DOMLSSerializerImpl::getParameter(const XMLCh* featName) const
00367 {
00368     if(XMLString::compareIStringASCII(featName, XMLUni::fgDOMErrorHandler)==0)
00369     {
00370         return (void*)fErrorHandler;
00371     }
00372     else
00373     {
00374         int featureId = INVALID_FEATURE_ID;
00375         checkFeature(featName, true, featureId);
00376         return (void*)getFeature(featureId);
00377     }
00378 }
00379 
00380 const DOMStringList* DOMLSSerializerImpl::getParameterNames() const
00381 {
00382     return fSupportedParameters;
00383 }
00384 
00385 void DOMLSSerializerImpl::setNewLine(const XMLCh* const newLine)
00386 {
00387     fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
00388     fNewLine = XMLString::replicate(newLine, fMemoryManager);
00389 }
00390 
00391 const XMLCh* DOMLSSerializerImpl::getNewLine() const
00392 {
00393     return fNewLine;
00394 }
00395 
00396 void DOMLSSerializerImpl::setFilter(DOMLSSerializerFilter *filter)
00397 {
00398     fFilter = filter;
00399 }
00400 
00401 DOMLSSerializerFilter* DOMLSSerializerImpl::getFilter() const
00402 {
00403     return fFilter;
00404 }
00405 
00406 //
00407 //
00408 //
00409 bool DOMLSSerializerImpl::write(const DOMNode* nodeToWrite,
00410                                 DOMLSOutput* const destination)
00411 {
00412     XMLFormatTarget* pTarget=destination->getByteStream();
00413     Janitor<XMLFormatTarget> janTarget(0);
00414     if(!pTarget)
00415     {
00416         const XMLCh* szSystemId=destination->getSystemId();
00417         if(!szSystemId)
00418         {
00419             //TODO: report error "missing target"
00420             return false;
00421         }
00422         pTarget=new LocalFileFormatTarget(szSystemId, fMemoryManager);
00423         janTarget.reset(pTarget);
00424     }
00436     fEncodingUsed = gUTF8;
00437 
00438     const DOMDocument *docu = (nodeToWrite->getNodeType() == DOMNode::DOCUMENT_NODE)?
00439                               (const DOMDocument*)nodeToWrite : nodeToWrite->getOwnerDocument();
00440 
00441     const XMLCh* lsEncoding=destination->getEncoding();
00442     if (lsEncoding && *lsEncoding)
00443     {
00444         fEncodingUsed = lsEncoding;
00445     }
00446     else if (docu)
00447     {
00448         const XMLCh* tmpEncoding = docu->getInputEncoding();
00449 
00450         if ( tmpEncoding && *tmpEncoding)
00451         {
00452             fEncodingUsed = tmpEncoding;
00453         }
00454         else
00455         {
00456             tmpEncoding = docu->getXmlEncoding();
00457 
00458             if ( tmpEncoding && *tmpEncoding)
00459             {
00460                 fEncodingUsed = tmpEncoding;
00461             }
00462         }
00463     }
00464 
00465 
00483     fNewLineUsed = (fNewLine && *fNewLine)? fNewLine : gEOLSeq;
00484 
00488     fDocumentVersion = (docu && docu->getXmlVersion() && *(docu->getXmlVersion()))?docu->getXmlVersion():XMLUni::fgVersion1_0;
00489 
00490     fErrorCount = 0;
00491 
00492     fLineFeedInTextNodePrinted = false;
00493     fLastWhiteSpaceInTextNode = 0;
00494 
00495     try
00496     {
00497         fFormatter = new (fMemoryManager) XMLFormatter( fEncodingUsed
00498                                                        ,fDocumentVersion
00499                                                        ,pTarget
00500                                                        ,XMLFormatter::NoEscapes
00501                                                        ,XMLFormatter::UnRep_CharRef
00502                                                        ,fMemoryManager);
00503     }
00504     catch (const TranscodingException& e)
00505     {
00506         reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());
00507         return false;
00508     }
00509 
00510     try
00511     {
00512         Janitor<XMLFormatter> janName(fFormatter);
00513         processNode(nodeToWrite);
00514         pTarget->flush();
00515     }
00516 
00517     //
00518     // The serialize engine (processNode) throws an exception to abort
00519     // serialization if
00520     //
00521     //   . A fatal error occurs which renders the output ill-formed, or
00522     //   . Instructed by the application's error handler
00523     //
00524     catch (const TranscodingException&)
00525     {
00526         pTarget->flush();
00527         return false;
00528     }
00529 
00530     catch (const XMLDOMMsg::Codes)
00531     {
00532         pTarget->flush();
00533         return false;
00534     }
00535     catch(const OutOfMemoryException&)
00536     {
00537         throw;
00538     }
00539     catch (...)
00540     {
00541         pTarget->flush();
00542         throw;
00543     }
00544 
00545     //
00546     // true if node was successfully serialized and
00547     // false in case a failure occured and the
00548     // failure wasn't canceled by the error handler.
00549     //
00550     return ((fErrorCount == 0)? true : false);
00551 }
00552 
00553 bool DOMLSSerializerImpl::writeToURI(const DOMNode* nodeToWrite, const XMLCh* uri)
00554 {
00555     DOMLSOutputImpl output(fMemoryManager);
00556     output.setSystemId(uri);
00557     return write(nodeToWrite, &output);
00558 }
00559 
00560 //
00561 // We don't throw DOMSTRING_SIZE_ERR since we are no longer
00562 // using DOMString.
00563 //
00564 XMLCh* DOMLSSerializerImpl::writeToString(const DOMNode* nodeToWrite, MemoryManager* manager /*= NULL*/)
00565 {
00566     if(manager==NULL)
00567         manager = fMemoryManager;
00568     MemBufFormatTarget  destination(1023, manager);
00569     bool retVal;
00570 
00571     bool bBOMFlag=getFeature(BYTE_ORDER_MARK_ID);
00572     setFeature(BYTE_ORDER_MARK_ID, false);
00573     try
00574     {
00575         DOMLSOutputImpl output(manager);
00576         output.setByteStream(&destination);
00577         output.setEncoding(XMLUni::fgUTF16EncodingString);
00578         retVal = write(nodeToWrite, &output);
00579     }
00580     catch(const OutOfMemoryException&)
00581     {
00582         throw;
00583     }
00584     catch (...)
00585     {
00586         //
00587         // there is a possibility that memory allocation
00588         // exception thrown in XMLBuffer class
00589         //
00590         setFeature(BYTE_ORDER_MARK_ID, bBOMFlag);
00591         return 0;
00592     }
00593 
00594     setFeature(BYTE_ORDER_MARK_ID, bBOMFlag);
00595     return (retVal ? XMLString::replicate((XMLCh*) destination.getRawBuffer(), manager) : 0);
00596 }
00597 
00598 //
00599 // Characters not representable in output encoding,
00600 //
00601 // 1. CHARACTER DATA (outside of markup)                --- no error
00602 //    ordinary character  -> numeric character reference
00603 //    '<' and '&'         -> &lt; and &amp;
00604 //
00605 // 2. Within MARKUP, but outside of attributes
00606 //    reported as an error                                 --- ERROR
00607 //    markup:
00608 //           start tag                                  done
00609 //           end tag                                    done
00610 //           empty element tag                          done
00611 //           entity references                          done
00612 //           character references    // REVISIT
00613 //           comments                                   done
00614 //           CDATA section delimiters                   done, done
00615 //           document type declarartions                done
00616 //           processing instructions (PI)               done
00617 //
00618 // 3. With in ATTRIBUTE
00619 //    -> numeric character reference
00620 //    no quotes                        -> in quotes
00621 //    with quotes, no apostrophe       -> in apostrophe
00622 //    with quotes and apostrophe       -> in quotes and &quot;
00623 //
00624 // 4. CDATA sections
00625 //    "split_cdata_section"  true                      --- char ref
00626 //                           false                     ---      ERROR
00627 //
00628 // ---------------------------------------------------------------------------
00629 //  Stream out a DOM node, and, recursively, all of its children. This
00630 //  function is the heart of writing a DOM tree out as XML source. Give it
00631 //  a document node and it will do the whole thing.
00632 // ---------------------------------------------------------------------------
00633 
00634 void DOMLSSerializerImpl::processNode(const DOMNode* const nodeToWrite, int level)
00635 {
00636 
00637     // Get the name and value out for convenience
00638     const XMLCh*    nodeName = nodeToWrite->getNodeName();
00639     const XMLCh*    nodeValue = nodeToWrite->getNodeValue();
00640     XMLSize_t       lent = XMLString::stringLen(nodeValue);
00641 
00642     switch (nodeToWrite->getNodeType())
00643     {
00644     case DOMNode::TEXT_NODE:
00645         {
00646             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
00647                 break;
00648 
00649             if (getFeature(FORMAT_PRETTY_PRINT_ID))
00650             {
00651                 fLineFeedInTextNodePrinted = false;
00652                 fLastWhiteSpaceInTextNode = 0;
00653 
00654                 if(XMLChar1_0::isAllSpaces(nodeValue, XMLString::stringLen(nodeValue)))
00655                 {
00656                     // skips whitespace-only text nodes unless whitespace-in-element is set.
00657                     if (!getFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID))
00658                     {
00659                         break;
00660                     }
00661                     else
00662                     {
00663                         //
00664                         // we need to trace if newline(s) have been printed out
00665                         // to avoid generate extra newline for pretty printing,
00666                         // as well as the number of whitespaces after the last
00667                         // newline character to do indentation properly.
00668                         //
00669                         int pos = XMLString::lastIndexOf(nodeValue, chLF);
00670                         if (-1 != pos)
00671                         {
00672                             fLineFeedInTextNodePrinted = true;
00673                             fLastWhiteSpaceInTextNode = (unsigned int)(lent - pos);
00674                         }
00675                         else
00676                         {
00677                             // for those platforms using chCR alone as
00678                             // a newline character
00679                             pos = XMLString::lastIndexOf(nodeValue, chCR);
00680                             if (-1 != pos)
00681                             {
00682                                 fLineFeedInTextNodePrinted = true;
00683                                 fLastWhiteSpaceInTextNode = (unsigned int)(lent - pos);
00684                             }
00685                         }
00686                     }
00687                 }
00688             }
00689 
00690             setURCharRef();      // character data
00691             fFormatter->formatBuf(nodeValue, lent, XMLFormatter::CharEscapes);
00692             break;
00693         }
00694 
00695     case DOMNode::PROCESSING_INSTRUCTION_NODE:
00696         {
00697             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
00698                 break;
00699 
00700             if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
00701                 printNewLine();
00702 
00703             printNewLine();
00704             printIndent(level);
00705 
00706             TRY_CATCH_THROW
00707             (
00708                 *fFormatter << XMLFormatter::NoEscapes << gStartPI << nodeName;
00709                 if (lent > 0)
00710                 {
00711                     *fFormatter << chSpace << nodeValue;
00712                 }
00713                 *fFormatter << gEndPI;
00714             )
00715             break;
00716         }
00717 
00718     case DOMNode::DOCUMENT_NODE: // Not to be shown to Filter
00719         {
00720 
00721             // output BOM if needed
00722             processBOM();
00723 
00724             setURCharRef();
00725             const DOMDocument *docu = (const DOMDocument*)nodeToWrite;
00726 
00727             //[23] XMLDecl      ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
00728             //[24] VersionInfo  ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
00729             //[80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName
00730             //[32] SDDecl       ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
00731             //
00732 
00733             if (getFeature(XML_DECLARATION)) {
00734                 // use the version and encoding resolved
00735                 *fFormatter << gXMLDecl_VersionInfo << fDocumentVersion << gXMLDecl_separator;
00736                 *fFormatter << gXMLDecl_EncodingDecl << fEncodingUsed << gXMLDecl_separator;
00737 
00738                 const XMLCh* st = (docu->getXmlStandalone())? XMLUni::fgYesString : XMLUni::fgNoString;
00739                 *fFormatter << gXMLDecl_SDDecl << st << gXMLDecl_separator;
00740 
00741                 *fFormatter << gXMLDecl_endtag;
00742             }
00743 
00744             DOMNodeSPtr child = nodeToWrite->getFirstChild();
00745             while( child != 0)
00746             {
00747                 processNode(child, level);
00748                 child = child->getNextSibling();
00749             }
00750             printNewLine();
00751             break;
00752         }
00753 
00754     case DOMNode::DOCUMENT_FRAGMENT_NODE:
00755         {
00756 
00757             setURCharRef();
00758 
00759             DOMNode *child = nodeToWrite->getFirstChild();
00760             while( child != 0)
00761             {
00762                 processNode(child, level);
00763                 child = child->getNextSibling();
00764             }
00765             printNewLine();
00766             break;
00767         }
00768 
00769     case DOMNode::ELEMENT_NODE:
00770         {
00771             DOMNodeFilter::FilterAction filterAction = checkFilter(nodeToWrite);
00772 
00773             if ( filterAction == DOMNodeFilter::FILTER_REJECT)
00774                 break;
00775 
00776             if (!fLineFeedInTextNodePrinted)
00777             {
00778                 if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
00779                     printNewLine();
00780 
00781                 printNewLine();
00782             }
00783             else
00784             {
00785                 fLineFeedInTextNodePrinted = false;
00786             }
00787 
00788             printIndent(level);
00789 
00790             //track the line number the current node begins on
00791             int nodeLine = fCurrentLine;
00792 
00793             // add an entry in the namespace stack
00794             RefHashTableOf<XMLCh>* namespaceMap=NULL;
00795 
00796             if ( filterAction == DOMNodeFilter::FILTER_ACCEPT)
00797             {
00798                 //           this element    attributes   child elements
00799                 // accept        yes             yes           yes
00800                 // skip          no              no            yes
00801                 //
00802                 TRY_CATCH_THROW
00803                 (
00804                 // The name has to be representable without any escapes
00805                     *fFormatter  << XMLFormatter::NoEscapes
00806                                  << chOpenAngle << nodeName;
00807                 )
00808 
00809                 // Output any attributes on this element
00810                 setURCharRef();
00811                 DOMNamedNodeMap *attributes = nodeToWrite->getAttributes();
00812                 XMLSize_t attrCount = attributes->getLength();
00813 
00814                 // check if the namespace for the current node is already defined
00815                 const XMLCh* prefix = nodeToWrite->getPrefix();
00816                 const XMLCh* uri = nodeToWrite->getNamespaceURI();
00817                 if((uri && uri[0]) || ((prefix==0 || prefix[0]==0) && isDefaultNamespacePrefixDeclared()))
00818                 {
00819                     if(prefix==0 || prefix[0]==0)
00820                         prefix=XMLUni::fgZeroLenString;
00821                     if(!isNamespaceBindingActive(prefix, uri))
00822                     {
00823                         if(namespaceMap==NULL)
00824                         {
00825                             namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
00826                             fNamespaceStack->addElement(namespaceMap);
00827                         }
00828                         namespaceMap->put((void*)prefix,(XMLCh*)uri);
00829                         *fFormatter  << XMLFormatter::NoEscapes
00830                                      << chSpace << XMLUni::fgXMLNSString;
00831                         if(!XMLString::equals(prefix,XMLUni::fgZeroLenString))
00832                             *fFormatter  << chColon << prefix;
00833                         *fFormatter  << chEqual << chDoubleQuote
00834                                      << XMLFormatter::AttrEscapes
00835                                      << uri
00836                                      << XMLFormatter::NoEscapes
00837                                      << chDoubleQuote;
00838                     }
00839                 }
00840 
00841                 bool discard = getFeature(DISCARD_DEFAULT_CONTENT_ID);
00842                 for (XMLSize_t i = 0; i < attrCount; i++)
00843                 {
00844                     DOMAttrSPtr  attribute = (DOMAttr*)attributes->item(i);
00845 
00846                     // Not to be shown to Filter
00847 
00848                     //
00849                     //"discard-default-content"
00850                     //    true
00851                     //    [required] (default)
00852                     //    Use whatever information available to the implementation
00853                     //  (i.e. XML schema, DTD, the specified flag on Attr nodes,
00854                     //  and so on) to decide what attributes and content should be
00855                     //  discarded or not.
00856                     //  Note that the specified flag on Attr nodes in itself is
00857                     //  not always reliable, it is only reliable when it is set
00858                     //  to false since the only case where it can be set to false
00859                     //  is if the attribute was created by the implementation.
00860                     //  The default content won't be removed if an implementation
00861                     //  does not have any information available.
00862                     //    false
00863                     //    [required]
00864                     //    Keep all attributes and all content.
00865                     //
00866                     if (discard && !((DOMAttr*)attribute )->getSpecified())
00867                         continue;
00868                     //
00869                     //  Again the name has to be completely representable. But the
00870                     //  attribute can have refs and requires the attribute style
00871                     //  escaping.
00872                     //
00873 
00874                     // if this attribute is a namespace declaration, add it to the namespace map for the current level
00875                     const XMLCh* ns = attribute->getNamespaceURI();
00876                     if (ns != 0 )
00877                     {
00878                         if(XMLString::equals(ns, XMLUni::fgXMLNSURIName))
00879                         {
00880                             if(namespaceMap==NULL)
00881                             {
00882                                 namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
00883                                 fNamespaceStack->addElement(namespaceMap);
00884                             }
00885                                         const XMLCh* nsPrefix = attribute->getLocalName();
00886                             if(XMLString::equals(attribute->getNodeName(),XMLUni::fgXMLNSString))
00887                                                                 nsPrefix = XMLUni::fgZeroLenString;
00888                                                         if(namespaceMap->containsKey((void*)nsPrefix))
00889                                                                 continue;
00890                             namespaceMap->put((void*)attribute->getLocalName(),(XMLCh*)attribute->getNodeValue());
00891                         }
00892                         else if(!XMLString::equals(ns, XMLUni::fgXMLURIName))
00893                         {
00894                             // check if the namespace for the current node is already defined
00895                             const XMLCh* prefix = attribute->getPrefix();
00896                             if(prefix && prefix[0])
00897                             {
00898                                 const XMLCh* uri = attribute->getNamespaceURI();
00899                                 if(!isNamespaceBindingActive(prefix, uri))
00900                                 {
00901                                     if(namespaceMap==NULL)
00902                                     {
00903                                         namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
00904                                         fNamespaceStack->addElement(namespaceMap);
00905                                     }
00906                                     namespaceMap->put((void*)prefix,(XMLCh*)uri);
00907                                     *fFormatter  << XMLFormatter::NoEscapes
00908                                                  << chSpace << XMLUni::fgXMLNSString << chColon << prefix
00909                                                  << chEqual << chDoubleQuote
00910                                                  << XMLFormatter::AttrEscapes
00911                                                  << uri
00912                                                  << XMLFormatter::NoEscapes
00913                                                  << chDoubleQuote;
00914                                 }
00915                             }
00916                         }
00917                     }
00918                     if (XMLString::equals(ns, XMLUni::fgXMLNSURIName) || checkFilter(attribute) == DOMNodeFilter::FILTER_ACCEPT)
00919                     {
00920                         *fFormatter  << XMLFormatter::NoEscapes
00921                                      << chSpace << attribute->getNodeName()
00922                                      << chEqual << chDoubleQuote
00923                                      << XMLFormatter::AttrEscapes;
00924                         if (getFeature(ENTITIES_ID))
00925                         {
00926                             DOMNodeSPtr child = attribute->getFirstChild();
00927                             while( child != 0)
00928                             {
00929                                 if(child->getNodeType()==DOMNode::TEXT_NODE)
00930                                     *fFormatter  << child->getNodeValue();
00931                                 else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
00932                                     *fFormatter << XMLFormatter::NoEscapes
00933                                                 << chAmpersand << child->getNodeName() << chSemiColon
00934                                                 << XMLFormatter::AttrEscapes;
00935                                 child = child->getNextSibling();
00936                             }
00937                         }
00938                         else
00939                             *fFormatter  << attribute->getNodeValue();
00940                         *fFormatter  << XMLFormatter::NoEscapes
00941                                      << chDoubleQuote;
00942                     }
00943                 } // end of for
00944             } // end of FILTER_ACCEPT
00945 
00946             level++;
00947 
00948             // FILTER_SKIP may start from here
00949 
00950             //
00951             //  Test for the presence of children, which includes both
00952             //  text content and nested elements.
00953             //
00954             DOMNodeSPtr child = nodeToWrite->getFirstChild();
00955             if (child != 0)
00956             {
00957                 // There are children. Close start-tag, and output children.
00958                 // No escapes are legal here
00959                 if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
00960                     *fFormatter << XMLFormatter::NoEscapes << chCloseAngle;
00961 
00962                 while( child != 0)
00963                 {
00964                     processNode(child, level);
00965                     child = child->getNextSibling();
00966                 }
00967 
00968                 level--;
00969 
00970                 if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
00971                 {
00972                     //if we are not on the same line as when we started
00973                     //this node then print a new line and indent
00974                     if(nodeLine != fCurrentLine)
00975                     {
00976                         if (!fLineFeedInTextNodePrinted)
00977                         {
00978                             printNewLine();
00979                         }
00980                         else
00981                         {
00982                             fLineFeedInTextNodePrinted = false;
00983                         }
00984 
00985                         if(nodeLine != fCurrentLine && level == 0 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
00986                             printNewLine();
00987 
00988                         printIndent(level);
00989                     }
00990                     TRY_CATCH_THROW
00991                     (
00992                          *fFormatter << XMLFormatter::NoEscapes << gEndElement
00993                                      << nodeName << chCloseAngle;
00994                     )
00995 
00996                 }
00997             }
00998             else
00999             {
01000                 level--;
01001 
01002                 //
01003                 //  There were no children. Output the short form close of
01004                 //  the element start tag, making it an empty-element tag.
01005                 //
01006                 if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
01007                 {
01008                     TRY_CATCH_THROW
01009                     (
01010                         *fFormatter << XMLFormatter::NoEscapes << chForwardSlash << chCloseAngle;
01011                     )
01012                 }
01013             }
01014 
01015             // remove the namespace map at this level
01016             if(namespaceMap!=NULL)
01017                 fNamespaceStack->removeLastElement();
01018 
01019             break;
01020         }
01021     case DOMNode::ATTRIBUTE_NODE:
01022         {
01023             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
01024                 break;
01025 
01026             const XMLCh* localName = nodeToWrite->getLocalName();
01027 
01028             // check if this is a DOM Level 1 Node
01029             if(localName == 0)
01030                 *fFormatter  << XMLFormatter::NoEscapes
01031                              << nodeToWrite->getNodeName();
01032             else
01033                 *fFormatter  << XMLFormatter::NoEscapes
01034                              << chOpenCurly << nodeToWrite->getNamespaceURI()
01035                              << chCloseCurly << localName;
01036             *fFormatter  << chEqual << chDoubleQuote
01037                          << XMLFormatter::AttrEscapes;
01038             if (getFeature(ENTITIES_ID))
01039             {
01040                 DOMNodeSPtr child = nodeToWrite->getFirstChild();
01041                 while( child != 0)
01042                 {
01043                     if(child->getNodeType()==DOMNode::TEXT_NODE)
01044                         *fFormatter  << child->getNodeValue();
01045                     else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
01046                         *fFormatter << XMLFormatter::NoEscapes
01047                                     << chAmpersand << child->getNodeName() << chSemiColon
01048                                     << XMLFormatter::AttrEscapes;
01049                     child = child->getNextSibling();
01050                 }
01051             }
01052             else
01053                 *fFormatter  << nodeValue;
01054             *fFormatter  << XMLFormatter::NoEscapes
01055                          << chDoubleQuote;
01056 
01057             break;
01058         }
01059     case DOMNode::ENTITY_REFERENCE_NODE:
01060         {
01061             //"entities"
01062             //true
01063             //[required] (default)
01064             //Keep EntityReference and Entity nodes in the document.
01065 
01066             //false
01067             //[optional]
01068             //Remove all EntityReference and Entity nodes from the document,
01069             //       putting the entity expansions directly in their place.
01070             //       Text nodes are into "normal" form.
01071             //Only EntityReference nodes to non-defined entities are kept in the document.
01072 
01073             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
01074                 break;
01075 
01076             if (getFeature(ENTITIES_ID))
01077             {
01078                 TRY_CATCH_THROW
01079                 (
01080                     *fFormatter << XMLFormatter::NoEscapes << chAmpersand
01081                                 << nodeName << chSemiColon;
01082                 )
01083             }
01084             else
01085             {
01086                 // check if the referenced entity is defined or not
01087                 if (nodeToWrite->getOwnerDocument()->getDoctype()->getEntities()->getNamedItem(nodeName))
01088                 {
01089                     DOMNodeSPtr child;
01090                     for (child = nodeToWrite->getFirstChild();
01091                     child != 0;
01092                     child = child->getNextSibling())
01093                     {
01094                         processNode(child, level);
01095                     }
01096                 }
01097                 else
01098                 {
01099                     TRY_CATCH_THROW
01100                    (
01101                         *fFormatter<<XMLFormatter::NoEscapes<<chAmpersand<<nodeName<<chSemiColon;
01102                     )
01103                 }
01104             }
01105             break;
01106         }
01107 
01108         //
01109         //  feature:split_cdata_sections     occurence of ]]>   unrep-char
01110         //  ===============================================================
01111         //          true                        split            split
01112         //          false                       fails            fails
01113         //
01114     case DOMNode::CDATA_SECTION_NODE:
01115         {
01116             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
01117                 break;
01118 
01119             if (getFeature(SPLIT_CDATA_SECTIONS_ID))
01120             {
01121                 // it is fairly complicated and we process this
01122                 // in a separate function.
01123                 procCdataSection(nodeValue, nodeToWrite);
01124             }
01125             else
01126             {
01127                 // search for "]]>", the node value is not supposed to have this
01128                 if (XMLString::patternMatch((XMLCh*) nodeValue, gEndCDATA) != -1)
01129                 {
01130                     reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NestedCDATA);
01131                 }
01132 
01133                 TRY_CATCH_THROW
01134                 (
01135                     // transcoder throws exception for unrep chars
01136                     *fFormatter << XMLFormatter::NoEscapes << gStartCDATA << nodeValue << gEndCDATA;
01137                 )
01138             }
01139 
01140             break;
01141         }
01142 
01143     case DOMNode::COMMENT_NODE:
01144         {
01145             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
01146                 break;
01147 
01148             // Figure out if we want pretty-printing for this comment.
01149             // If this comment node does not have any element siblings
01150             // (i.e., it is a text node) then we don't want to add any
01151             // whitespaces since that might be significant to the
01152             // application. Otherwise we want pretty-printing.
01153             //
01154 
01155             bool pretty = (level == 0); // Document-level comments.
01156 
01157             if (!pretty)
01158             {
01159               // See if we have any element siblings.
01160               //
01161               const DOMNode* s = nodeToWrite->getNextSibling ();
01162 
01163               while (s != 0 && s->getNodeType () != DOMNode::ELEMENT_NODE)
01164                 s = s->getNextSibling ();
01165 
01166               if (s != 0)
01167                 pretty = true;
01168               else
01169               {
01170                 s = nodeToWrite->getPreviousSibling ();
01171 
01172                 while (s != 0 && s->getNodeType () != DOMNode::ELEMENT_NODE)
01173                   s = s->getPreviousSibling ();
01174 
01175                 if (s != 0)
01176                   pretty = true;
01177               }
01178             }
01179 
01180             if (pretty)
01181             {
01182               if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
01183                 printNewLine();
01184 
01185               printNewLine();
01186               printIndent(level);
01187             }
01188 
01189             TRY_CATCH_THROW
01190             (
01191                 *fFormatter << XMLFormatter::NoEscapes << gStartComment
01192                 << nodeValue << gEndComment;
01193             )
01194             break;
01195         }
01196 
01197     case DOMNode::DOCUMENT_TYPE_NODE:  // Not to be shown to Filter
01198         {
01199             const DOMDocumentType *doctype = (const DOMDocumentType *)nodeToWrite;
01200 
01201             fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);
01202 
01203             printNewLine();
01204             printIndent(level);
01205 
01206             TRY_CATCH_THROW
01207             (
01208                 *fFormatter << gStartDoctype << nodeName;
01209 
01210                 const XMLCh  *id = doctype->getPublicId();
01211                 if (id && *id)
01212                 {
01213                     *fFormatter << chSpace << gPublic << id << chDoubleQuote;
01214 
01215                     id = doctype->getSystemId();
01216                     if (id && *id)
01217                     {
01218                         *fFormatter << chSpace << chDoubleQuote << id << chDoubleQuote;
01219                     }
01220                     else
01221                     {
01222                         //
01223                         // 4.2.2 External Entities
01224                         // [Definition: If the entity is not internal,
01225                         //           it is an external entity, declared as follows:]
01226                         // External Entity Declaration
01227                         // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
01228                         //                   | 'PUBLIC' S PubidLiteral S SystemLiteral
01229                         //
01230                         reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
01231                         // systemLiteral not found
01232                     }
01233                 }
01234                 else
01235                 {
01236                     id = doctype->getSystemId();
01237                     if (id && *id)
01238                     {
01239                         *fFormatter << chSpace << gSystem << id << chDoubleQuote;
01240                     }
01241                 }
01242 
01243                 id = doctype->getInternalSubset();
01244                 if (id && *id)
01245                 {
01246                     *fFormatter << chSpace << chOpenSquare << id << chCloseSquare;
01247                 }
01248 
01249                 *fFormatter << chCloseAngle;
01250             ) // end of TRY_CATCH_THROW
01251 
01252             break;
01253         }
01254 
01255     case DOMNode::ENTITY_NODE:  // Not to be shown to Filter
01256         {
01257             //
01258             // REVISIT: how does the feature "entities" impact
01259             // entity node?
01260             //
01261             printNewLine();
01262             printIndent(level);
01263 
01264             fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);
01265             *fFormatter << gStartEntity    << nodeName;
01266 
01267             const XMLCh * id = ((const DOMEntity*)nodeToWrite)->getPublicId();
01268             if (id)
01269                 *fFormatter << gPublic << id << chDoubleQuote;
01270 
01271             id = ((const DOMEntity*)nodeToWrite)->getSystemId();
01272             if (id)
01273                 *fFormatter << gSystem << id << chDoubleQuote;
01274 
01275             id = ((const DOMEntity*)nodeToWrite)->getNotationName();
01276             if (id)
01277                 *fFormatter << gNotation << id << chDoubleQuote;
01278 
01279             *fFormatter << chCloseAngle;
01280 
01281             break;
01282         }
01283 
01284     default:
01285         /***
01286             This is an implementation specific behaviour, we abort if a user derived class has not dealt with
01287             this node type.
01288          ***/
01289         {
01290             if(!customNodeSerialize(nodeToWrite, level)) {
01291                 reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
01292                 // UnreognizedNodeType;
01293             }
01294         }
01295 
01296         break;
01297     }
01298 
01299 }
01300 
01301 bool DOMLSSerializerImpl::customNodeSerialize(const DOMNode* const, int) {
01302     return false;
01303 }
01304 
01305 //
01306 //
01307 DOMNodeFilter::FilterAction DOMLSSerializerImpl::checkFilter(const DOMNode* const node) const
01308 {
01309     if (!fFilter ||
01310         ((fFilter->getWhatToShow() & (1 << (node->getNodeType() - 1))) == 0))
01311         return DOMNodeFilter::FILTER_ACCEPT;
01312 
01313     //
01314     // if and only if there is a filter, and it is interested
01315     // in the node type, then we pass the node to the filter
01316     // for examination
01317     //
01318     return (DOMNodeFilter::FilterAction) fFilter->acceptNode(node);
01319 }
01320 
01321 
01322 bool DOMLSSerializerImpl::checkFeature(const XMLCh* const featName
01323                                , bool               toThrow
01324                                , int&               featureId) const
01325 {
01326     // check for null and/or empty feature name
01327     if (!featName || !*featName)
01328     {
01329         if (toThrow)
01330             throw DOMException(DOMException::NOT_FOUND_ERR, 0, fMemoryManager);
01331 
01332         return false;
01333     }
01334 
01335     featureId = INVALID_FEATURE_ID;
01336 
01337     if (XMLString::equals(featName, XMLUni::fgDOMWRTCanonicalForm))
01338         featureId = CANONICAL_FORM_ID;
01339     else if (XMLString::equals(featName, XMLUni::fgDOMWRTDiscardDefaultContent))
01340         featureId = DISCARD_DEFAULT_CONTENT_ID;
01341     else if (XMLString::equals(featName, XMLUni::fgDOMWRTEntities))
01342         featureId = ENTITIES_ID;
01343     else if (XMLString::equals(featName, XMLUni::fgDOMWRTFormatPrettyPrint))
01344         featureId = FORMAT_PRETTY_PRINT_ID;
01345     else if (XMLString::equals(featName, XMLUni::fgDOMWRTNormalizeCharacters))
01346         featureId = NORMALIZE_CHARACTERS_ID;
01347     else if (XMLString::equals(featName, XMLUni::fgDOMWRTSplitCdataSections))
01348         featureId = SPLIT_CDATA_SECTIONS_ID;
01349     else if (XMLString::equals(featName, XMLUni::fgDOMWRTValidation))
01350         featureId = VALIDATION_ID;
01351     else if (XMLString::equals(featName, XMLUni::fgDOMWRTWhitespaceInElementContent))
01352         featureId = WHITESPACE_IN_ELEMENT_CONTENT_ID;
01353     else if (XMLString::equals(featName, XMLUni::fgDOMWRTBOM))
01354         featureId = BYTE_ORDER_MARK_ID;
01355     else if (XMLString::equals(featName, XMLUni::fgDOMXMLDeclaration))
01356         featureId = XML_DECLARATION;
01357     else if (XMLString::equals(featName, XMLUni::fgDOMWRTXercesPrettyPrint))
01358         featureId = FORMAT_PRETTY_PRINT_1ST_LEVEL_ID;
01359 
01360 
01361     //feature name not resolvable
01362     if (featureId == INVALID_FEATURE_ID)
01363     {
01364         if (toThrow)
01365             throw DOMException(DOMException::NOT_FOUND_ERR, 0, fMemoryManager);
01366 
01367         return false;
01368     }
01369 
01370     return true;
01371 }
01372 
01373 bool DOMLSSerializerImpl::reportError(const DOMNode* const    errorNode
01374                               , DOMError::ErrorSeverity errorType
01375                               , const XMLCh*   const    errorMsg)
01376 {
01377     bool toContinueProcess = true;   // default value for no error handler
01378 
01379     if (fErrorHandler)
01380     {
01381         DOMLocatorImpl  locator(0, 0, (DOMNode*) errorNode, 0);
01382         DOMErrorImpl    domError(errorType , errorMsg, &locator);
01383         try
01384         {
01385             toContinueProcess = fErrorHandler->handleError(domError);
01386         }
01387         catch(...)
01388         {
01389         }
01390     }
01391 
01392     if (errorType != DOMError::DOM_SEVERITY_WARNING)
01393         fErrorCount++;
01394 
01395     return toContinueProcess;
01396 }
01397 
01398 bool DOMLSSerializerImpl::reportError(const DOMNode* const    errorNode
01399                               , DOMError::ErrorSeverity errorType
01400                               , XMLDOMMsg::Codes        toEmit)
01401 {
01402     const XMLSize_t msgSize = 1023;
01403     XMLCh errText[msgSize + 1];
01404 
01405     DOMImplementationImpl::getMsgLoader4DOM()->loadMsg(toEmit, errText, msgSize);
01406 
01407     bool toContinueProcess = true;   // default value for no error handler
01408 
01409     if (fErrorHandler)
01410     {
01411         DOMLocatorImpl  locator(0, 0, (DOMNode*) errorNode, 0);
01412         DOMErrorImpl    domError(errorType , errText, &locator);
01413         try
01414         {
01415             toContinueProcess = fErrorHandler->handleError(domError);
01416         }
01417         catch(...)
01418         {
01419         }
01420     }
01421 
01422     if (errorType != DOMError::DOM_SEVERITY_WARNING)
01423         fErrorCount++;
01424 
01425     if (errorType == DOMError::DOM_SEVERITY_FATAL_ERROR || !toContinueProcess)
01426         throw toEmit;
01427 
01428     return toContinueProcess;
01429 }
01430 
01431 //
01432 //
01433 //
01434 void DOMLSSerializerImpl::procCdataSection(const XMLCh*   const nodeValue
01435                                    , const DOMNode* const nodeToWrite)
01436 {
01437     static const XMLSize_t offset = XMLString::stringLen(gEndCDATA);
01438 
01439     /***
01440      * Append a ']]>' at the end
01441      */
01442     XMLSize_t len = XMLString::stringLen(nodeValue);
01443     XMLCh* repNodeValue = (XMLCh*) fMemoryManager->allocate
01444     (
01445         (len + offset + 1) * sizeof(XMLCh)
01446     );//new XMLCh [len + offset + 1];
01447     XMLString::copyString(repNodeValue, nodeValue);
01448     XMLString::catString(repNodeValue, gEndCDATA);
01449     ArrayJanitor<XMLCh>  jName(repNodeValue, fMemoryManager);
01450 
01451     XMLCh* curPtr  = (XMLCh*) repNodeValue;
01452     XMLCh* nextPtr = 0;
01453     int    endTagPos = -1;
01454 
01455     bool   endTagFound = true;
01456 
01457     while (endTagFound)
01458     {
01459         endTagPos = XMLString::patternMatch(curPtr, gEndCDATA);
01460         if (endTagPos != -1)
01461         {
01462             nextPtr = curPtr + endTagPos + offset;  // skip the ']]>'
01463             *(curPtr + endTagPos) = chNull;         //nullify the first ']'
01464             if (XMLSize_t(endTagPos) != len)
01465                 reportError(nodeToWrite, DOMError::DOM_SEVERITY_WARNING, XMLDOMMsg::Writer_NestedCDATA);
01466             len = len - endTagPos - offset;
01467         }
01468         else
01469         {
01470             endTagFound = false;
01471         }
01472 
01473         /***
01474             to check ]]>]]>
01475         ***/
01476         if (endTagPos == 0)
01477         {
01478             TRY_CATCH_THROW
01479             (
01480                 *fFormatter << XMLFormatter::NoEscapes << gStartCDATA << gEndCDATA;
01481             )
01482         }
01483         else
01484         {
01485             procUnrepCharInCdataSection(curPtr, nodeToWrite);
01486         }
01487 
01488         if (endTagFound)
01489         {
01490             *(nextPtr - offset) = chCloseSquare;   //restore the first ']'
01491             curPtr = nextPtr;
01492         }
01493     }
01494 }
01495 
01496 //
01497 //
01498 //
01499 void DOMLSSerializerImpl::procUnrepCharInCdataSection(const XMLCh*   const nodeValue
01500                                               , const DOMNode* const nodeToWrite)
01501 {
01502     //
01503     //  We have to check each character and see if it could be represented.
01504     //  As long as it can, we just keep up with where we started and how
01505     //  many chars we've checked. When we hit an unrepresentable one, we
01506     //  stop, transcode everything we've collected, then start handling
01507     //  the unrepresentables via char refs. We repeat this until we get all
01508     //  the chars done.
01509     //
01510     const XMLCh*    srcPtr = nodeValue;
01511     const XMLCh*    endPtr = nodeValue +  XMLString::stringLen(nodeValue);
01512 
01513     // Set up the common part of the buffer that we build char refs into
01514     XMLCh tmpBuf[32];
01515     tmpBuf[0] = chAmpersand;
01516     tmpBuf[1] = chPound;
01517     tmpBuf[2] = chLatin_x;
01518 
01519     while (srcPtr < endPtr)
01520     {
01521         const XMLCh* tmpPtr = srcPtr;
01522         while (tmpPtr < endPtr)
01523         {
01524             if (fFormatter->getTranscoder()->canTranscodeTo(*tmpPtr))
01525                 tmpPtr++;
01526             else
01527                 break;
01528         }
01529 
01530         if (tmpPtr > srcPtr)
01531         {
01532             TRY_CATCH_THROW
01533             (
01534                 *fFormatter << XMLFormatter::NoEscapes << gStartCDATA;
01535             )
01536 
01537             // We got at least some chars that can be done normally
01538             fFormatter->formatBuf
01539             (
01540                 srcPtr
01541                 , tmpPtr - srcPtr
01542                 , XMLFormatter::NoEscapes
01543                 , XMLFormatter::UnRep_Fail
01544             );
01545 
01546             TRY_CATCH_THROW
01547             (
01548                 *fFormatter << XMLFormatter::NoEscapes << gEndCDATA;
01549             )
01550 
01551             // Update the source pointer to our new spot
01552             srcPtr = tmpPtr;
01553         }
01554         else
01555         {
01556             //
01557             //  We hit something unrepresentable. So continue forward doing
01558             //  char refs until we hit something representable again or the
01559             //  end of input.
01560             //
01561 
01562             // one warning for consective unrep chars
01563             reportError(nodeToWrite, DOMError::DOM_SEVERITY_WARNING, XMLDOMMsg::Writer_NotRepresentChar);
01564 
01565             while (srcPtr < endPtr)
01566             {
01567                 // Build a char ref for the current char
01568                 XMLString::binToText(*srcPtr, &tmpBuf[3], 8, 16, fMemoryManager);
01569                 const XMLSize_t bufLen = XMLString::stringLen(tmpBuf);
01570                 tmpBuf[bufLen] = chSemiColon;
01571                 tmpBuf[bufLen+1] = chNull;
01572 
01573                 // And now call recursively back to our caller to format this
01574                 fFormatter->formatBuf
01575                 (
01576                     tmpBuf
01577                     , bufLen + 1
01578                     , XMLFormatter::NoEscapes
01579                     , XMLFormatter::UnRep_Fail
01580                 );
01581 
01582                 // Move up the source pointer and break out if needed
01583                 srcPtr++;
01584                 if (fFormatter->getTranscoder()->canTranscodeTo(*srcPtr))
01585                     break;
01586             }
01587         }
01588     }
01589 }
01590 
01591 void DOMLSSerializerImpl::processNode(const DOMNode* const nodeToWrite)
01592 {
01593     processNode(nodeToWrite, 0);
01594 }
01595 
01596 bool DOMLSSerializerImpl::canSetFeature(const int featureId
01597                                        , bool      val) const
01598 {
01599     return featuresSupported[2*featureId + (val? 0: 1)];
01600 }
01601 
01602 void DOMLSSerializerImpl::printNewLine()
01603 {
01604     if (getFeature(FORMAT_PRETTY_PRINT_ID))
01605     {
01606         fCurrentLine++;
01607         *fFormatter << fNewLineUsed;
01608     }
01609 }
01610 
01611 void DOMLSSerializerImpl::printIndent(unsigned int level)
01612 {
01613     if (getFeature(FORMAT_PRETTY_PRINT_ID))
01614     {
01615         if (fLastWhiteSpaceInTextNode)
01616         {
01617             unsigned int indentLevel = fLastWhiteSpaceInTextNode/2; // two chSpaces equals one indent level
01618             fLastWhiteSpaceInTextNode = 0;
01619             // if fLastWhiteSpaceInTextNode/2 is greater than level, then
01620             // it means too many spaces have been written to the
01621             // output stream and we can no longer indent properly
01622             if(indentLevel < level)
01623                 level -= indentLevel;
01624             else
01625                 level = 0;
01626         }
01627 
01628         for(unsigned int i = 0; i < level; i++)
01629             *fFormatter << chSpace << chSpace;
01630     }
01631 }
01632 
01633 void DOMLSSerializerImpl::release()
01634 {
01635     DOMLSSerializerImpl* writer = (DOMLSSerializerImpl*) this;
01636     delete writer;
01637 }
01638 
01639 void DOMLSSerializerImpl::processBOM()
01640 {
01641     // if the feature is not set, don't output bom
01642     if (!getFeature(BYTE_ORDER_MARK_ID))
01643         return;
01644 
01645     if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF8EncodingString)  == 0) ||
01646         (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF8EncodingString2) == 0)  )
01647     {
01648         fFormatter->writeBOM(BOM_utf8, 3);
01649     }
01650     else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16LEncodingString)  == 0) ||
01651         (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16LEncodingString2) == 0)  )
01652     {
01653         fFormatter->writeBOM(BOM_utf16le, 2);
01654     }
01655     else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16BEncodingString)  == 0) ||
01656              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16BEncodingString2) == 0)  )
01657     {
01658         fFormatter->writeBOM(BOM_utf16be, 2);
01659     }
01660     else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString)  == 0) ||
01661              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString2) == 0) ||
01662              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString3) == 0) ||
01663              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString4) == 0) ||
01664              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString5) == 0) ||
01665              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString6) == 0) ||
01666              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString7) == 0)  )
01667     {
01668         if (XMLPlatformUtils::fgXMLChBigEndian)
01669             fFormatter->writeBOM(BOM_utf16be, 2);
01670         else
01671             fFormatter->writeBOM(BOM_utf16le, 2);
01672     }
01673     else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4LEncodingString)  == 0) ||
01674              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4LEncodingString2) == 0)  )
01675     {
01676         fFormatter->writeBOM(BOM_ucs4le, 4);
01677     }
01678     else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4BEncodingString)  == 0) ||
01679              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4BEncodingString2) == 0)  )
01680     {
01681         fFormatter->writeBOM(BOM_ucs4be, 4);
01682     }
01683     else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString)  == 0) ||
01684              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString2) == 0) ||
01685              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString3) == 0) ||
01686              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString4) == 0) ||
01687              (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString5) == 0)  )
01688     {
01689                 if (XMLPlatformUtils::fgXMLChBigEndian)
01690                 fFormatter->writeBOM(BOM_ucs4be, 4);
01691             else
01692                         fFormatter->writeBOM(BOM_ucs4le, 4);
01693     }
01694 }
01695 
01696 bool DOMLSSerializerImpl::isDefaultNamespacePrefixDeclared() const
01697 {
01698     for(XMLSize_t i=fNamespaceStack->size();i>0;i--)
01699     {
01700         RefHashTableOf<XMLCh>* curNamespaceMap=fNamespaceStack->elementAt(i-1);
01701         const XMLCh* thisUri=curNamespaceMap->get((void*)XMLUni::fgZeroLenString);
01702         if(thisUri)
01703             return true;
01704     }
01705     return false;
01706 }
01707 
01708 bool DOMLSSerializerImpl::isNamespaceBindingActive(const XMLCh* prefix, const XMLCh* uri) const
01709 {
01710     for(XMLSize_t i=fNamespaceStack->size();i>0;i--)
01711     {
01712         RefHashTableOf<XMLCh>* curNamespaceMap=fNamespaceStack->elementAt(i-1);
01713         const XMLCh* thisUri=curNamespaceMap->get((void*)prefix);
01714         // if the prefix has been declared, check if it binds to the correct namespace, otherwise, reports it isn't bound
01715         if(thisUri)
01716             return XMLString::equals(thisUri,uri);
01717     }
01718     return false;
01719 }
01720 
01721 XERCES_CPP_NAMESPACE_END