GME
13
|
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 '&' -> < and & 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 " 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