Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache\@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their featName, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation, and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.ibm.com . For more information
* on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
* $Id$
* $Log$
* Revision 1.45 2003/11/24 12:27:57 gareth
* added in support for xml-declaration feature.
*
* Revision 1.44 2003/11/24 11:10:58 gareth
* Fix for bug 22917. Patch by Adam Heinz .
*
* Revision 1.43 2003/11/10 17:52:58 amassari
* Fixed memory leak
*
Neil Graham
committed
* Revision 1.42 2003/10/01 16:32:37 neilg
* improve handling of out of memory conditions, bug #23415. Thanks to David Cargill.
*
* Revision 1.41 2003/08/14 16:31:13 gareth
* Method added to allow serilization of custom nodes from derived classes.
*
* Revision 1.40 2003/08/12 12:46:57 gareth
* Added serialization for attribute nodes. Patch by Caroline Rioux.
*
* Revision 1.39 2003/05/18 14:02:03 knoaman
* Memory manager implementation: pass per instance manager.
*
Khaled Noaman
committed
* Revision 1.38 2003/05/16 21:36:55 knoaman
* Memory manager implementation: Modify constructors to pass in the memory manager.
*
* Revision 1.37 2003/05/15 18:25:54 knoaman
* Partial implementation of the configurable memory manager.
*
Gareth Reakes
committed
* Revision 1.36 2003/05/14 16:20:13 gareth
* Fix to problem with multiple default namespace attributes being serialized. Patch by Alberto Massari.
*
Gareth Reakes
committed
* Revision 1.35 2003/05/12 16:08:11 gareth
* fix to #18832. Corrected serilization with regards to namespace nodes. Patch by Alby Massari.
*
* Revision 1.34 2003/05/06 13:48:35 neilg
* fix GCC compilation problem and incorrect #include
*
Neil Graham
committed
* Revision 1.33 2003/05/05 21:23:21 neilg
* use of the new DOMNodeSPtr typedef and its friends to enable reference counting in
* the DOMWriter implementation for applications that require it.
*
* Revision 1.32 2003/04/02 03:14:42 peiyongz
* Bug#18594: DOMWriter does not recognize Document Fragment
*
* Revision 1.31 2003/03/16 05:42:04 peiyongz
* Bug#17983 Formatter does not escape control characters
*
* Revision 1.30 2003/02/25 16:07:37 tng
* [Bug 13493] Use const on static data in DOMWriterImpl.cpp.
*
* Revision 1.29 2003/01/28 18:31:47 peiyongz
* Bug#13694: Allow Xerces to write the BOM to XML files
*
* Revision 1.28 2003/01/24 20:21:46 tng
* DOMWriter: Call XMLFormatTarget::flush when done.
*
* Revision 1.27 2003/01/20 16:50:13 tng
* DOMWriter fix:
* 1. wrong wrong nested cdata message
* 2. pretty format the cdata section
* 3. do not increment error count if warning was issued
*
* Revision 1.26 2003/01/09 19:53:45 tng
* [Bug 15372] DOMBuilder::parseFromURI ignores result of handleErrors.
*
Tinny Ng
committed
* Revision 1.25 2002/12/10 21:01:32 tng
* NLS: DOMWriter should use message loader to load message instead of using hardcoded static stirng
*
* Revision 1.24 2002/12/10 18:59:14 tng
* pretty format print: consistent newline
*
* Revision 1.23 2002/12/10 13:34:07 tng
* Pretty-format print: also indent PI/comment that appear inside the root element.
*
* Revision 1.22 2002/12/09 11:46:08 gareth
* More pretty pretty print feature. Patch by Kevin King. Closes bug #13840.
*
* Revision 1.21 2002/12/02 23:08:09 peiyongz
* fix to bug#14528: output n+1 cdatasection
*
* Revision 1.20 2002/11/13 21:51:22 peiyongz
* fix to Bug#14528
*
* Revision 1.19 2002/11/04 15:07:35 tng
* C++ Namespace Support.
*
* Revision 1.18 2002/10/03 18:13:38 peiyongz
* Bug#12560 Use const in DOMWriter - patch from Duncan Stodart
* (Duncan_Stodart@insession.com )
*
* Revision 1.17 2002/09/24 20:19:14 tng
* Performance: use XMLString::equals instead of XMLString::compareString
* and check for null string directly isntead of calling XMLString::stringLen
*
* Revision 1.16 2002/09/09 15:42:14 peiyongz
* Patch to Bug#12369: invalid output from DOMWriter using MemBufFormatTarget
*
* Revision 1.15 2002/08/07 18:10:19 peiyongz
* Fix to Bug#11534: Wrong CDATA Terminator in DOMWriterImpl
*
* Revision 1.14 2002/07/22 23:24:01 tng
* DOM L3: writeToString should use the fFormatter to do the transcoding
*
* Revision 1.13 2002/07/16 15:19:42 peiyongz
* check lenght of getEncoding()/getActualEncoding()
*
* Revision 1.12 2002/06/25 16:17:16 tng
* DOM L3: add release()
*
* Revision 1.11 2002/06/21 19:33:12 peiyongz
* support for feature split_cdata_section and entities revised.
*
PeiYong Zhang
committed
* Revision 1.10 2002/06/18 15:35:25 peiyongz
* Bug#9950: Compilation error on MSVC5, patch from PeterV@ti.com.od.ua (Peter A. Volchek)
*
* Revision 1.9 2002/06/17 19:45:58 peiyongz
* optimization on fFeatures and featureId introduced
*
* Revision 1.8 2002/06/11 19:45:45 peiyongz
* Notify application of the XMLFormatter creation failure
*
* Revision 1.7 2002/06/10 16:02:21 peiyongz
* format-pretty-print partially supported
* resolve encoding from DOMDocument Interface
*
* Revision 1.6 2002/06/06 20:58:37 tng
* [Bug 9639] enum_mem in DOMError clashes with constant.
*
* Revision 1.5 2002/06/05 16:03:03 peiyongz
* delete[] used.
*
* Revision 1.4 2002/06/03 22:35:54 peiyongz
* constants changed
*
* Revision 1.3 2002/05/31 21:01:06 peiyongz
* move printing of XMLDecl into the processNode().
*
Khaled Noaman
committed
* Revision 1.2 2002/05/29 21:31:50 knoaman
* DOM L3 LS: DOMInputSource, DOMEntityResolver, DOMImplementationLS and DOMBuilder
*
* Revision 1.1 2002/05/28 22:39:39 peiyongz
* DOM3 Save Interface: DOMWriter/DOMWriterFilter
*
*/
Khaled Noaman
committed
#include "DOMWriterImpl.hpp"
#include "DOMErrorImpl.hpp"
#include "DOMLocatorImpl.hpp"
Tinny Ng
committed
#include "DOMImplementationImpl.hpp"
#include <xercesc/framework/MemBufFormatTarget.hpp>
#include <xercesc/util/TransService.hpp>
#include <xercesc/util/TranscodingException.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
Tinny Ng
committed
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/dom/StDOMNode.hpp>
Neil Graham
committed
#include <xercesc/util/OutOfMemoryException.hpp>
// ---------------------------------------------------------------------------
// Local const data
//
// ---------------------------------------------------------------------------
static const int INVALID_FEATURE_ID = -1;
static const int CANONICAL_FORM_ID = 0x0;
static const int DISCARD_DEFAULT_CONTENT_ID = 0x1;
static const int ENTITIES_ID = 0x2;
static const int FORMAT_PRETTY_PRINT_ID = 0x3;
static const int NORMALIZE_CHARACTERS_ID = 0x4;
static const int SPLIT_CDATA_SECTIONS_ID = 0x5;
static const int VALIDATION_ID = 0x6;
static const int WHITESPACE_IN_ELEMENT_CONTENT_ID = 0x7;
static const int BYTE_ORDER_MARK_ID = 0x8;
static const int XML_DECLARATIION = 0x9;
// feature true false
// ================================================================================
//canonical-form [optional] Not Supported [required] (default)
//discard-default-content [required] (default) [required]
//entity [required] (default) [optional]
//format-pretty-print [optional] Partially Supported [required] (default)
//normalize-characters [optional] Not Supported [required] (default)
//split-cdata-sections [required] (default) [required]
//validation [optional] Not Supported [required] (default)
//whitespace-in-element-content [requierd] (default) [optional] Not Supported
//
//
// the first for "true",
// the second for "false".
//
static const bool featuresSupported[] = {
false, true, // canonical-form
true, true, // discard-default-content
true, true, // entity
true, true, // format-pretty-print
false, true, // normalize-characters
true, true, // split-cdata-sections
false, true, // validation
true, false, // whitespace-in-element-content
true, true, // byte-order-mark
true, true // xml-declaration
};
// default end-of-line sequence
static const XMLCh gEOLSeq[] =
{
chLF, chNull
};
//UTF-8
static const XMLCh gUTF8[] =
{
chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull
};
//</
static const XMLCh gEndElement[] =
{
chOpenAngle, chForwardSlash, chNull
};
//?>
static const XMLCh gEndPI[] =
chQuestion, chCloseAngle, chNull
static const XMLCh gStartPI[] =
{
chOpenAngle, chQuestion, chNull
//<?xml version="
static const XMLCh gXMLDecl_VersionInfo[] =
chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l, chSpace,
chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i, chLatin_o,
chLatin_n, chEqual, chDoubleQuote, chNull
};
static const XMLCh gXMLDecl_ver10[] =
{
chDigit_1, chPeriod, chDigit_0, chNull
};
//encoding="
static const XMLCh gXMLDecl_EncodingDecl[] =
{
chLatin_e, chLatin_n, chLatin_c, chLatin_o, chLatin_d, chLatin_i,
chLatin_n, chLatin_g, chEqual, chDoubleQuote, chNull
};
//" standalone="
static const XMLCh gXMLDecl_SDDecl[] =
{
chLatin_s, chLatin_t, chLatin_a, chLatin_n, chLatin_d, chLatin_a,
chLatin_l, chLatin_o, chLatin_n, chLatin_e, chEqual, chDoubleQuote,
static const XMLCh gXMLDecl_separator[] =
chDoubleQuote, chSpace, chNull
//?>
static const XMLCh gXMLDecl_endtag[] =
chQuestion, chCloseAngle, chNull
};
//<![CDATA[
static const XMLCh gStartCDATA[] =
{
chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
};
//]]>
static const XMLCh gEndCDATA[] =
{
// chCloseSquare, chCloseAngle, chCloseAngle, chNull // test only: ]>>
chCloseSquare, chCloseSquare, chCloseAngle, chNull
static const int offset = XMLString::stringLen(gEndCDATA);
//<!--
static const XMLCh gStartComment[] =
{
chOpenAngle, chBang, chDash, chDash, chNull
};
//-->
static const XMLCh gEndComment[] =
{
chDash, chDash, chCloseAngle, chNull
};
static const XMLCh gStartDoctype[] =
{
chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T,
chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull
};
//PUBLIC "
static const XMLCh gPublic[] =
{
chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I,
chLatin_C, chSpace, chDoubleQuote, chNull
};
//SYSTEM "
static const XMLCh gSystem[] =
{
chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E,
chLatin_M, chSpace, chDoubleQuote, chNull
};
static const XMLCh gStartEntity[] =
{
chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I,
chLatin_T, chLatin_Y, chSpace, chNull
};
//NDATA "
static const XMLCh gNotation[] =
{
chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A,
chSpace, chDoubleQuote, chNull
};
static const XMLCh gFeature[] =
{
chLatin_F, chLatin_e, chLatin_a, chLatin_t, chLatin_u, chLatin_r,
chLatin_e, chSpace, chNull
};
static const XMLCh gCantSet[] =
{
chSpace, chLatin_C, chLatin_a, chLatin_n, chSpace, chLatin_n, chLatin_o,
chLatin_t, chSpace, chLatin_b, chLatin_e, chSpace, chLatin_s,
chLatin_e, chLatin_t, chSpace, chLatin_t, chLatin_o, chSpace, chNull
};
static const XMLCh gTrue[] =
{
chSingleQuote, chLatin_t, chLatin_r, chLatin_u, chLatin_e,
chSingleQuote, chLF, chNull
};
static const XMLCh gFalse[] =
{
chSingleQuote, chLatin_f, chLatin_a, chLatin_l, chLatin_s,
chLatin_e, chSingleQuote, chLF, chNull
};
static const XMLByte BOM_utf16be[] = {(XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
static const XMLByte BOM_utf16le[] = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte) 0};
static const XMLByte BOM_ucs4be[] = {(XMLByte)0x00, (XMLByte)0x00, (XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
static const XMLByte BOM_ucs4le[] = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte)0x00, (XMLByte)0x00, (XMLByte) 0};
Gareth Reakes
committed
static const XMLCh s_xmlnsURI[] = // "http://www.w3.org/2000/xmlns/"
{ chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash, chForwardSlash,
chLatin_w, chLatin_w, chLatin_w, chPeriod, chLatin_w, chDigit_3, chPeriod,
chLatin_o, chLatin_r, chLatin_g, chForwardSlash,
chDigit_2, chDigit_0, chDigit_0, chDigit_0, chForwardSlash,
chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chForwardSlash, chNull};
static const XMLCh s_xmlns[] = {chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chNull};
static const XMLCh s_xmlURI[] = // "http://www.w3.org/XML/1998/namespace"
{ chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash, chForwardSlash,
chLatin_w, chLatin_w, chLatin_w, chPeriod, chLatin_w, chDigit_3, chPeriod,
chLatin_o, chLatin_r, chLatin_g, chForwardSlash, chLatin_X, chLatin_M, chLatin_L, chForwardSlash,
chDigit_1, chDigit_9, chDigit_9, chDigit_8, chForwardSlash,
chLatin_n, chLatin_a, chLatin_m, chLatin_e, chLatin_s, chLatin_p, chLatin_a, chLatin_c, chLatin_e,
chNull};
//
// Notification of the error though error handler
//
// The application may instruct the engine to abort serialization
// by returning "false".
//
// REVISIT: update the locator ctor once the line#, col#, uri and offset
// are available from DOM3 core
//
// REVISIT: use throwing exception to abort serialization is an interesting
// thing here, since the serializer is a recusive function, we
// can't use return, obviously. However we may have multiple try/catch
// along its way going back to writeNode(). So far we don't come up with a
// "short-cut" to go "directly" back.
//
#define TRY_CATCH_THROW(action, forceToRethrow) \
fFormatter->setUnRepFlags(XMLFormatter::UnRep_Fail); \
try \
{ \
action; \
} \
catch(TranscodingException const &e) \
{ \
if ( !reportError(nodeToWrite \
, DOMError::DOM_SEVERITY_FATAL_ERROR \
, e.getMessage()) || \
forceToRethrow) \
throw e; \
}
DOMWriterImpl::~DOMWriterImpl()
{
fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
Gareth Reakes
committed
delete fNamespaceStack;
// we don't own/adopt error handler and filter
DOMWriterImpl::DOMWriterImpl(MemoryManager* const manager)
:fFeatures(0)
,fEncoding(0)
,fNewLine(0)
,fErrorHandler(0)
,fFilter(0)
,fDocumentVersion(XMLUni::fgVersion1_0)
,fEncodingUsed(0)
,fNewLineUsed(0)
,fFormatter(0)
,fErrorCount(0)
,fCurrentLine(0)
Gareth Reakes
committed
,fNamespaceStack(0)
,fMemoryManager(manager)
fNamespaceStack=new (fMemoryManager) RefVectorOf< RefHashTableOf<XMLCh> >(0,true, fMemoryManager);
Gareth Reakes
committed
//
// set features to default setting
//
setFeature(CANONICAL_FORM_ID, false);
setFeature(DISCARD_DEFAULT_CONTENT_ID, true );
setFeature(ENTITIES_ID, true );
setFeature(FORMAT_PRETTY_PRINT_ID, false);
setFeature(NORMALIZE_CHARACTERS_ID, false);
setFeature(SPLIT_CDATA_SECTIONS_ID, true );
setFeature(VALIDATION_ID, false);
setFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID, true );
setFeature(BYTE_ORDER_MARK_ID, false);
setFeature(XML_DECLARATIION, true );
bool DOMWriterImpl::canSetFeature(const XMLCh* const featName
, bool state) const
int featureId = INVALID_FEATURE_ID;
return checkFeature(featName, false, featureId) ? canSetFeature(featureId, state) : false;
}
void DOMWriterImpl::setFeature(const XMLCh* const featName
, bool state)
{
int featureId = INVALID_FEATURE_ID;
checkFeature(featName, true, featureId);
if (!canSetFeature(featureId, state))
{
XMLCh tmpbuf[256];
XMLString::copyString(tmpbuf, gFeature);
XMLString::catString(tmpbuf, featName);
XMLString::catString(tmpbuf, gCantSet);
XMLString::catString(tmpbuf, state? gTrue : gFalse);
throw DOMException(DOMException::NOT_SUPPORTED_ERR, tmpbuf);
else
setFeature(featureId, state);
//
// canonical-form and format-pretty-print can not be both set to true
// meaning set canonical-form true will automatically set
// format-pretty-print to false and vise versa.
if ((featureId == CANONICAL_FORM_ID) && state)
setFeature(FORMAT_PRETTY_PRINT_ID, false);
if ((featureId == FORMAT_PRETTY_PRINT_ID) && state)
setFeature(CANONICAL_FORM_ID, false);
}
bool DOMWriterImpl::getFeature(const XMLCh* const featName) const
{
int featureId = INVALID_FEATURE_ID;
checkFeature(featName, true, featureId);
return getFeature(featureId);
}
// we don't check the validity of the encoding set
void DOMWriterImpl::setEncoding(const XMLCh* const encoding)
{
fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
fEncoding = XMLString::replicate(encoding, fMemoryManager);
}
const XMLCh* DOMWriterImpl::getEncoding() const
{
return fEncoding;
}
void DOMWriterImpl::setNewLine(const XMLCh* const newLine)
{
fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
fNewLine = XMLString::replicate(newLine, fMemoryManager);
}
const XMLCh* DOMWriterImpl::getNewLine() const
{
return fNewLine;
}
void DOMWriterImpl::setErrorHandler(DOMErrorHandler *errorHandler)
{
fErrorHandler = errorHandler;
}
DOMErrorHandler* DOMWriterImpl::getErrorHandler() const
{
return fErrorHandler;
}
void DOMWriterImpl::setFilter(DOMWriterFilter *filter)
{
fFilter = filter;
}
DOMWriterFilter* DOMWriterImpl::getFilter() const
{
return fFilter;
}
//
//
//
bool DOMWriterImpl::writeNode(XMLFormatTarget* const destination
, const DOMNode &nodeToWrite)
{
//init session vars
initSession(&nodeToWrite);
fFormatter = new (fMemoryManager) XMLFormatter(fEncodingUsed
,fDocumentVersion
,destination
,XMLFormatter::NoEscapes
,XMLFormatter::UnRep_CharRef);
}
catch (const TranscodingException& e)
{
reportError(&nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());
return false;
}
try
{
Janitor<XMLFormatter> janName(fFormatter);
processNode(&nodeToWrite);
}
//
// The serialize engine (processNode) throws an exception to abort
// serialization if
//
// . A fatal error occurs which renters the output ill-formed, or
// . Instructed by the application's error handler
//
catch (const TranscodingException&)
{
return false;
}
Tinny Ng
committed
catch (const XMLDOMMsg::Codes)
{
return false;
}
Neil Graham
committed
catch(const OutOfMemoryException&)
{
throw;
}
//
// DOMSystemException
// This exception will be raised in response to any sort of IO or system
// error that occurs while writing to the destination. It may wrap an
// underlying system exception.
//
//catch (RuntimeException const &)
catch (...)
{
// REVISIT generate a DOMSystemException wrapping the underlying
// exception.
throw;
}
//
// true if node was successfully serialized and
// false in case a failure occured and the
// failure wasn't canceled by the error handler.
//
return ((fErrorCount == 0)? true : false);
}
//
// We don't throw DOMSTRING_SIZE_ERR since we are no longer
// using DOMString.
//
XMLCh* DOMWriterImpl::writeToString(const DOMNode &nodeToWrite)
{
Khaled Noaman
committed
MemBufFormatTarget destination(1023, fMemoryManager);
bool retVal;
// XMLCh is unicode, assume fEncoding as UTF-16
XMLCh* tempEncoding = fEncoding;
fEncoding = (XMLCh*) XMLUni::fgUTF16EncodingString;
try
{
retVal = writeNode(&destination, nodeToWrite);
}
Neil Graham
committed
catch(const OutOfMemoryException&)
{
throw;
}
catch (...)
{
//
// there is a possibility that memeory allocation
// exception thrown in XMLBuffer class
//
fEncoding = tempEncoding;
return 0;
}
fEncoding = tempEncoding;
return (retVal ? XMLString::replicate((XMLCh*) destination.getRawBuffer(), fMemoryManager) : 0);
}
void DOMWriterImpl::initSession(const DOMNode* const nodeToWrite)
{
/**
* The encoding to use when writing is determined as follows:
* If the encoding attribute has been set, that value will be used.
* If the encoding attribute is null or empty,
* but the item to be written, or
* the owner document specified encoding (ie. the "actualEncoding"
* from the document) that value will be used.
* If neither of the above provides an encoding name, a default encoding of
*/
fEncodingUsed = gUTF8;
if (fEncoding && *fEncoding)
{
fEncodingUsed = fEncoding;
}
else
{
const DOMDocument *docu = (nodeToWrite->getNodeType() == DOMNode::DOCUMENT_NODE)?
(const DOMDocument*)nodeToWrite : nodeToWrite->getOwnerDocument();
const XMLCh* tmpEncoding = docu->getEncoding();
if ( tmpEncoding && *tmpEncoding)
fEncodingUsed = tmpEncoding;
tmpEncoding = docu->getActualEncoding();
if ( tmpEncoding && *tmpEncoding)
{
fEncodingUsed = tmpEncoding;
}
/**
* The end-of-line sequence of characters to be used in the XML being
* written out. The only permitted values are these:
* . null
*
* Use a default end-of-line sequence. DOM implementations should choose
* the default to match the usual convention for text files in the
* environment being used. Implementations must choose a default
* sequence that matches one of those allowed by 2.11 "End-of-Line
* Handling".
*
* CR The carriage-return character (#xD)
* CR-LF The carriage-return and line-feed characters (#xD #xA)
* LF The line-feed character (#xA)
*
* The default value for this attribute is null
*/
fNewLineUsed = (fNewLine && *fNewLine)? fNewLine : gEOLSeq;
/**
* get Document Version
*/
const DOMDocument *docu = (nodeToWrite->getNodeType() == DOMNode::DOCUMENT_NODE)?
(const DOMDocument*)nodeToWrite : nodeToWrite->getOwnerDocument();
if (docu)
{
fDocumentVersion = docu->getVersion();
}
fErrorCount = 0;
}
//
// Characters not representable in output encoding,
//
// 1. CHARACTER DATA (outside of markup) --- no error
// ordinary character -> numeric character reference
// '<' and '&' -> < and &
// 2. Within MARKUP, but outside of attributes
// reported as an error --- ERROR
// markup:
// start tag done
// end tag done
// empty element tag done
// entity references done
// character references // REVISIT
// comments done
// CDATA section delimiters done, done
// document type declarartions done
// processing instructions (PI) done
//
// 3. With in ATTRIBUTE
// -> numeric character reference
// no quotes -> in quotes
// with quotes, no apostrophe -> in apostrophe
// with quotes and apostrophe -> in quotes and "
//
// "split_cdata_section" true --- char ref
// false --- ERROR
//
// ---------------------------------------------------------------------------
// Stream out a DOM node, and, recursively, all of its children. This
// function is the heart of writing a DOM tree out as XML source. Give it
// a document node and it will do the whole thing.
// ---------------------------------------------------------------------------
void DOMWriterImpl::processNode(const DOMNode* const nodeToWrite, int level)
// Get the name and value out for convenience
const XMLCh* nodeName = nodeToWrite->getNodeName();
const XMLCh* nodeValue = nodeToWrite->getNodeValue();
unsigned long lent = XMLString::stringLen(nodeValue);
switch (nodeToWrite->getNodeType())
{
case DOMNode::TEXT_NODE:
if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
break;
// Pretty-print skips whitespace-only text nodes unless whitespace-in-element is set.
if (getFeature(FORMAT_PRETTY_PRINT_ID) && !getFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID))
{
if(XMLString::isAllWhiteSpace(nodeValue))
break;
}
setURCharRef(); // character data
fFormatter->formatBuf(nodeValue, lent, XMLFormatter::CharEscapes);
break;
}
case DOMNode::PROCESSING_INSTRUCTION_NODE:
if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
break;
if(level == 1)
printNewLine();
printNewLine();
printIndent(level);
TRY_CATCH_THROW
(
*fFormatter << XMLFormatter::NoEscapes << gStartPI << nodeName;
if (lent > 0)
{
*fFormatter << chSpace << nodeValue;
}
*fFormatter << gEndPI;
,true
)
case DOMNode::DOCUMENT_NODE: // Not to be shown to Filter
// output BOM if needed
processBOM();
setURCharRef();
const DOMDocument *docu = (const DOMDocument*)nodeToWrite;
//[23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
//[24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
//[80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName
//[32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
if (getFeature(XML_DECLARATIION)) {
const XMLCh* versionNo = (docu->getVersion()) ? docu->getVersion() : gXMLDecl_ver10;
*fFormatter << gXMLDecl_VersionInfo << versionNo << gXMLDecl_separator;
// use the encoding resolved in initSession()
*fFormatter << gXMLDecl_EncodingDecl << fEncodingUsed << gXMLDecl_separator;
const XMLCh* st = (docu->getStandalone())? XMLUni::fgYesString : XMLUni::fgNoString;
*fFormatter << gXMLDecl_SDDecl << st << gXMLDecl_separator;
*fFormatter << gXMLDecl_endtag;
}
Neil Graham
committed
DOMNodeSPtr child = nodeToWrite->getFirstChild();
processNode(child, level);
child = child->getNextSibling();
}
printNewLine();
break;
}
case DOMNode::DOCUMENT_FRAGMENT_NODE:
{
setURCharRef();
DOMNode *child = nodeToWrite->getFirstChild();
while( child != 0)
{
processNode(child, level);
child = child->getNextSibling();
}
case DOMNode::ELEMENT_NODE:
DOMNodeFilter::FilterAction filterAction = checkFilter(nodeToWrite);
if ( filterAction == DOMNodeFilter::FILTER_REJECT)
break;
if(level == 1)
printNewLine();
printNewLine();
printIndent(level);
//track the line number the current node begins on
int nodeLine = fCurrentLine;
// add an entry in the namespace stack
RefHashTableOf<XMLCh>* namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
fNamespaceStack->addElement(namespaceMap);
Gareth Reakes
committed
if ( filterAction == DOMNodeFilter::FILTER_ACCEPT)
{
// this element attributes child elements
// skip no no yes
//
TRY_CATCH_THROW
(
// The name has to be representable without any escapes
*fFormatter << XMLFormatter::NoEscapes
<< chOpenAngle << nodeName;
,true
)
// Output any attributes on this element
setURCharRef();
DOMNamedNodeMap *attributes = nodeToWrite->getAttributes();
int attrCount = attributes->getLength();
Gareth Reakes
committed
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// check if the namespace for the current node is already defined
const XMLCh* prefix = nodeToWrite->getPrefix();
const XMLCh* uri = nodeToWrite->getNamespaceURI();
if(uri && uri[0])
{
if(prefix==0 || prefix[0]==0)
prefix=XMLUni::fgZeroLenString;
bool bPrefixDeclared=false;
for(int i=fNamespaceStack->size()-1;i>=0;i--)
{
RefHashTableOf<XMLCh>* curNamespaceMap=fNamespaceStack->elementAt(i);
const XMLCh* thisUri=curNamespaceMap->get((void*)prefix);
if(thisUri && XMLString::equals(thisUri,nodeToWrite->getNamespaceURI()))
{
bPrefixDeclared=true;
break;
}
}
if(!bPrefixDeclared)
{
namespaceMap->put((void*)prefix,(XMLCh*)nodeToWrite->getNamespaceURI());
*fFormatter << XMLFormatter::NoEscapes
<< chSpace << s_xmlns;
if(!XMLString::equals(prefix,XMLUni::fgZeroLenString))
*fFormatter << chColon << prefix;
*fFormatter << chEqual << chDoubleQuote
<< XMLFormatter::AttrEscapes