text: //
  // XMLWriter.h
  //
  // Library: XML
  // Package: XML
  // Module:  XMLWriter
  //
  // Definition of the XMLWriter class.
  //
  // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  // and Contributors.
  //
  // SPDX-License-Identifier:	BSL-1.0
  //
  
  
  #ifndef XML_XMLWriter_INCLUDED
  #define XML_XMLWriter_INCLUDED
  
  
  #include "Poco/XML/XML.h"
  #include "Poco/SAX/ContentHandler.h"
  #include "Poco/SAX/LexicalHandler.h"
  #include "Poco/SAX/DTDHandler.h"
  #include "Poco/SAX/NamespaceSupport.h"
  #include "Poco/XML/XMLString.h"
  #include "Poco/XML/XMLStream.h"
  #include "Poco/XML/Name.h"
  #include "Poco/TextEncoding.h"
  #include "Poco/StreamConverter.h"
  #include <vector>
  #include <map>
  
  
  namespace Poco {
  namespace XML {
  
  
  class Locator;
  
  
  class XML_API XMLWriter: public ContentHandler, public LexicalHandler, public DTDHandler
  	/// This class serializes SAX2 ContentHandler, LexicalHandler and
  	/// DTDHandler events back into a stream.
  	/// 
  	/// Various consistency checks are performed on the written data
  	/// (i.e. there must be exactly one root element and every startElement() 
  	/// must have a matching endElement()).
  	///
  	/// The XMLWriter supports optional pretty-printing of the serialized XML.
  	/// Note, however, that pretty-printing XML data alters the
  	/// information set of the document being written, since in
  	/// XML all whitespace is potentially relevant to an application.
  	///
  	/// The writer contains extensive support for XML Namespaces, so that a client  
  	/// application does not have to keep track of prefixes and supply xmlns attributes.
  	///
  	/// If the client does not provide namespace prefixes (either by specifying them
  	/// as part of the qualified name given to startElement(), or by calling
  	/// startPrefixMapping()), the XMLWriter automatically generates namespace
  	/// prefixes in the form ns1, ns2, etc.
  {
  public:
  	enum Options
  	{
  		CANONICAL               = 0x00,
  			/// Do not write an XML declaration (default).
  
  		CANONICAL_XML           = 0x01, 
  			/// Enables basic support for Canonical XML: 
  			///   - do not write an XML declaration
  			///   - do not use special empty element syntax
  			///   - set the New Line character to NEWLINE_LF
  			///   - write namespace declarations and attributes 
  			///     in canonical order
  			///   - use default namespace as much as possible
  
  		WRITE_XML_DECLARATION   = 0x02, 
  			/// Write an XML declaration.
  
  		PRETTY_PRINT            = 0x04, 
  			/// Pretty-print XML markup.
  
  		PRETTY_PRINT_ATTRIBUTES = 0x08
  			/// Write each attribute on a separate line. 
  			/// PRETTY_PRINT must be specified as well.
  	};
  
  	XMLWriter(XMLByteOutputStream& str, int options);
  		/// Creates the XMLWriter and sets the specified options.
  		///
  		/// The resulting stream will be UTF-8 encoded.
  
  	XMLWriter(XMLByteOutputStream& str, int options, const std::string& encodingName, Poco::TextEncoding& textEncoding);
  		/// Creates the XMLWriter and sets the specified options.
  		///
  		/// The encoding is reflected in the XML declaration.
  		/// The caller is responsible for that the given encodingName matches with
  		/// the given textEncoding.
  
  	XMLWriter(XMLByteOutputStream& str, int options, const std::string& encodingName, Poco::TextEncoding* pTextEncoding);
  		/// Creates the XMLWriter and sets the specified options.
  		///
  		/// The encoding is reflected in the XML declaration.
  		/// The caller is responsible for that the given encodingName matches with
  		/// the given textEncoding.
  		/// If pTextEncoding is null, the given encodingName is ignored and the
  		/// default UTF-8 encoding is used.
  
  	~XMLWriter();
  		/// Destroys the XMLWriter.
  
  	void setNewLine(const std::string& newLineCharacters);
  		/// Sets the line ending for the resulting XML file.
  		///
  		/// Possible values are:
  		///   * NEWLINE_DEFAULT (whatever is appropriate for the current platform)
  		///   * NEWLINE_CRLF    (Windows),
  		///   * NEWLINE_LF      (Unix),
  		///   * NEWLINE_CR      (Macintosh)
  
  	const std::string& getNewLine() const;
  		/// Returns the line ending currently in use.
  
  	void setIndent(const std::string& indent);
  		/// Sets the string used for one indentation step.
  		///
  		/// The default is a single TAB character.
  		/// The given string should only contain TAB or SPACE
  		/// characters (e.g., a single TAB character, or
  		/// two to four SPACE characters).
  		
  	const std::string& getIndent() const;
  		/// Returns the string used for one indentation step.
  
  	// ContentHandler
  	void setDocumentLocator(const Locator* loc);
  		/// Currently unused.
  
  	void startDocument();
  		/// Writes a generic XML declaration to the stream.
  		/// If a document type has been set (see SetDocumentType),
  		/// a DOCTYPE declaration is also written.
  
  	void endDocument();
  		/// Checks that all elements are closed and prints a final newline.
  
  	void startFragment();
  		/// Use this instead of StartDocument() if you want to write
  		/// a fragment rather than a document (no XML declaration and
  		/// more than one "root" element allowed).
  
  	void endFragment();
  		/// Checks that all elements are closed and prints a final newline.
  
  	void startElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname, const Attributes& attributes);
  		/// Writes an XML start element tag.
  		///
  		/// Namespaces are handled as follows.
  		///   1. If a qname, but no namespaceURI and localName are given, the qname is taken as element name.
  		///   2. If a namespaceURI and a localName, but no qname is given, and the given namespaceURI has been
  		///      declared earlier, the namespace prefix for the given namespaceURI together with the localName
  		///      is taken as element name. If the namespace has not been declared, a prefix in the form
  		///      "ns1", "ns2", etc. is generated and the namespace is declared with the generated prefix.
  		///   3. If all three are given, and the namespace given in namespaceURI has not been declared, it is declared now.
  		///      Otherwise, see 2.
  
  	void startElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname);
  		/// Writes an XML start element tag with no attributes.
  		/// See the other startElement() method for more information.
  		
  	void endElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname);
  		/// Writes an XML end element tag.
  		///
  		/// Throws an exception if the name of doesn't match the
  		/// one of the most recent startElement().
  
  	void emptyElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname);
  		/// Writes an empty XML element tag (<elem/>).
  
  	void emptyElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname, const Attributes& attributes);
  		/// Writes an empty XML element tag with the given attributes (<elem attr1="value1"... />).
  
  	void characters(const XMLChar ch[], int start, int length);
  		/// Writes XML character data. Quotes, ampersand's, less-than and
  		/// greater-than signs are escaped, unless a CDATA section
  		/// has been opened by calling startCDATA().
  		///
  		/// The characters must be encoded in UTF-8 (if XMLChar is char) or 
  		/// UTF-16 (if XMLChar is wchar_t).
  
  	void characters(const XMLString& str);
  		/// Writes XML character data. Quotes, ampersand's, less-than and
  		/// greater-than signs are escaped, unless a CDATA section
  		/// has been opened by calling startCDATA().
  		///
  		/// The characters must be encoded in UTF-8 (if XMLChar is char) or 
  		/// UTF-16 (if XMLChar is wchar_t).
  
  	void rawCharacters(const XMLString& str);
  		/// Writes the characters in the given string as they are.
  		/// The caller is responsible for escaping characters as
  		/// necessary to produce valid XML.
  		///
  		/// The characters must be encoded in UTF-8 (if XMLChar is char) or 
  		/// UTF-16 (if XMLChar is wchar_t).
  
  	void ignorableWhitespace(const XMLChar ch[], int start, int length);
  		/// Writes whitespace characters by simply passing them to
  		/// characters().
  
  	void processingInstruction(const XMLString& target, const XMLString& data);
  		/// Writes a processing instruction.
  
  	void startPrefixMapping(const XMLString& prefix, const XMLString& namespaceURI);
  		/// Begin the scope of a prefix-URI Namespace mapping.
  		/// A namespace declaration is written with the next element.
  
  	void endPrefixMapping(const XMLString& prefix);
  		/// End the scope of a prefix-URI mapping.
  
  	void skippedEntity(const XMLString& name);
  		/// Does nothing.
  
  	void dataElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname, const XMLString& data, 
  	                         const XMLString& attr1 = XMLString(), const XMLString& value1 = XMLString(),
  							 const XMLString& attr2 = XMLString(), const XMLString& value2 = XMLString(),
  							 const XMLString& attr3 = XMLString(), const XMLString& value3 = XMLString());
  		/// Writes a data element in the form <name attr1="value1"...>data</name>.
  
  	// LexicalHandler
  	void startCDATA();
  		/// Writes the <![CDATA[ string that begins a CDATA section.
  		/// Use characters() to write the actual character data.
  
  	void endCDATA();
  		/// Writes the ]]> string that ends a CDATA section.
  
  	void comment(const XMLChar ch[], int start, int length);
  		/// Writes a comment.
  
  	void startDTD(const XMLString& name, const XMLString& publicId, const XMLString& systemId);
  		/// Writes a DTD declaration.
  
  	void endDTD();
  		/// Writes the closing characters of a DTD declaration.
  
  	void startEntity(const XMLString& name);
  		/// Does nothing.
  
  	void endEntity(const XMLString& name);
  		/// Does nothing.
  	
  	// DTDHandler
  	void notationDecl(const XMLString& name, const XMLString* publicId, const XMLString* systemId);
  	void unparsedEntityDecl(const XMLString& name, const XMLString* publicId, const XMLString& systemId, const XMLString& notationName);
  
  	static const std::string NEWLINE_DEFAULT;
  	static const std::string NEWLINE_CR;
  	static const std::string NEWLINE_CRLF;
  	static const std::string NEWLINE_LF;
  
  	// Namespace support.
  	XMLString uniquePrefix();
  		/// Creates and returns a unique namespace prefix that
  		/// can be used with startPrefixMapping().
  
  	bool isNamespaceMapped(const XMLString& namespc) const;
  		/// Returns true if the given namespace has been mapped
  		/// to a prefix in the current element or its ancestors.
  		
  	// Misc.
  	int depth() const;
  		/// Return the number of nested XML elements.
  		///
  		/// Will be -1 if no document or fragment has been started, 
  		/// 0 if the document or fragment has been started,
  		/// 1 if the document element has been written and
  		/// > 1 for every element nested within the document element.
  
  protected:
  	typedef std::map<XMLString, XMLString> AttributeMap;
  	typedef std::map<XMLString, std::pair<XMLString, XMLString> > CanonicalAttributeMap;
  
  	void writeStartElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname, const Attributes& attributes);
  	void writeCanonicalStartElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname, const Attributes& attributes);
  	void writeEndElement(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname);
  	void writeMarkup(const std::string& str) const;
  	void writeXML(const XMLString& str) const;
  	void writeXML(XMLChar ch) const;
  	void writeNewLine() const;
  	void writeIndent() const;
  	void writeIndent(int indent) const;
  	void writeName(const XMLString& prefix, const XMLString& localName);
  	void writeXMLDeclaration();
  	void closeStartTag();
  	void declareNamespaces(const XMLString& namespaceURI, const XMLString& localName, const XMLString& qname, const Attributes& attributes);
  	void declareAttributeNamespaces(const Attributes& attributes);
  	void addNamespaceAttributes(AttributeMap& attributeMap);
  	void addNamespaceAttributes(CanonicalAttributeMap& attributeMap);
  	void addAttributes(AttributeMap& attributeMap, const Attributes& attributes, const XMLString& elementNamespaceURI);
  	void addAttributes(CanonicalAttributeMap& attributeMap, const Attributes& attributes, const XMLString& elementNamespaceURI);
  	void writeAttributes(const AttributeMap& attributeMap);
  	void writeAttributes(const CanonicalAttributeMap& attributeMap);
  	void prettyPrint() const;
  	static std::string nameToString(const XMLString& localName, const XMLString& qname);
  
  private:
  	struct Namespace
  	{
  		Namespace(const XMLString& thePrefix, const XMLString& theNamespaceURI):
  			prefix(thePrefix),
  			namespaceURI(theNamespaceURI)
  		{
  		}
  
  		XMLString prefix;
  		XMLString namespaceURI;
  	};
  	typedef std::vector<Name> ElementStack;
  	
  	Poco::OutputStreamConverter* _pTextConverter;
  	Poco::TextEncoding*          _pInEncoding;
  	Poco::TextEncoding*          _pOutEncoding;
  	int              _options;
  	std::string      _encoding;
  	std::string      _newLine;
  	int              _depth;
  	int              _elementCount;
  	bool             _inFragment;
  	bool             _inCDATA;
  	bool             _inDTD;
  	bool             _inInternalDTD;
  	bool             _contentWritten;
  	bool             _unclosedStartTag;
  	ElementStack     _elementStack;
  	NamespaceSupport _namespaces;
  	int              _prefix;
  	bool             _nsContextPushed;
  	std::string      _indent;
  
  	static const std::string MARKUP_QUOTENC;
  	static const std::string MARKUP_AMPENC;
  	static const std::string MARKUP_LTENC;
  	static const std::string MARKUP_GTENC;
  	static const std::string MARKUP_TABENC;
  	static const std::string MARKUP_CRENC;
  	static const std::string MARKUP_LFENC;
  	static const std::string MARKUP_LT;
  	static const std::string MARKUP_GT;
  	static const std::string MARKUP_SLASHGT;
  	static const std::string MARKUP_LTSLASH;
  	static const std::string MARKUP_COLON;
  	static const std::string MARKUP_EQQUOT;
  	static const std::string MARKUP_QUOT;
  	static const std::string MARKUP_SPACE;
  	static const std::string MARKUP_TAB;
  	static const std::string MARKUP_BEGIN_CDATA;
  	static const std::string MARKUP_END_CDATA;
  };
  
  
  //
  // inlines
  //
  inline int XMLWriter::depth() const
  {
  	return _depth;
  }
  
  
  } } // namespace Poco::XML
  
  
  #endif // XML_XMLWriter_INCLUDED
  