1
0
mirror of https://github.com/pocoproject/poco.git synced 2025-03-23 23:49:26 +01:00

Add RoundTrip example for XML Streaming API + backport lates libstudxml changes from upstream

This commit is contained in:
Marian Krivos 2015-08-23 14:38:57 +02:00
parent ce003c5522
commit eca1119c82
8 changed files with 615 additions and 30 deletions

@ -55,8 +55,16 @@ public:
void startElement(const QName& qname);
void startElement(const std::string& name);
void startElement(const std::string& ns, const std::string& name);
void endElement();
// "Checked" end element. That is, it checks that the element
// you think you are ending matches the current one.
//
void endElement (const QName& qname);
void endElement (const std::string& name);
void endElement (const std::string& ns, const std::string& name);
// Helpers for serializing elements with simple content. The first two
// functions assume that startElement() has already been called. The
// other two serialize the complete element, from start to end.
@ -79,7 +87,17 @@ public:
void startAttribute(const QName& qname);
void startAttribute(const std::string& name);
void startAttribute(const std::string& ns, const std::string& name);
void endAttribute();
// "Checked" end attribute. That is, it checks that the attribute
// you think you are ending matches the current one.
//
void endAttribute (const QName& qname);
void endAttribute (const std::string& name);
void endAttribute (const std::string& ns, const std::string& name);
void attribute(const QName& qname, const std::string& value);
template<typename T>
void attribute(const QName& qname, const T& value);
@ -100,23 +118,61 @@ public:
/// Namespaces declaration. If prefix is empty, then the default
/// namespace is declared. If both prefix and namespace are empty,
/// then the default namespace declaration is cleared (xmlns="").
/// This function should be called after start_element().
void xmlDecl(const std::string& version = "1.0", const std::string& encoding = "UTF-8", const std::string& standalone = "");
/// XML declaration. If encoding or standalone are not specified,
/// then these attributes are omitted from the output.
// DOCTYPE declaration. If encoding or standalone are not specified,
// then these attributes are omitted from the output.
//
void doctypeDecl (const std::string& root_element,
const std::string& public_id = "",
const std::string& system_id = "",
const std::string& internal_subset = "");
// Utility functions.
//
bool lookupNamespacePrefix(const std::string& ns, std::string& prefix);
bool lookupNamespacePrefix(const std::string& ns, std::string& prefix) const;
/// Return true if there is a mapping. In this case, prefix contains
/// the mapped prefix.
// Return the current element, that is, the latest element for which
// start_element() but not endElement() have been called.
//
QName currentElement () const;
// Return the current attribute, that is, the latest attribute for
// which start_attribute() but not endAttribute() have been called.
//
QName currentAttribute () const;
// Suspend/resume indentation.
//
// Indentation can be suspended only inside an element and, unless
// explicitly resumed, it will remain suspended until the end of
// that element. You should only explicitly resume indentation at
// the element nesting level of suspension. If indentation is already
// suspended at an outer nesting level, then subsequent calls to
// suspend/resume are ignored. The indentation_suspended() function
// can be used to check if indentation is currently suspended. If it
// is not, then this function returns 0. Otherwise, it returns the
// level at which pretty-printing was suspended, with root element
// being level 1.
//
void suspendIndentation ();
void resumeIndentation ();
std::size_t indentationSuspended () const;
private:
XMLStreamSerializer(const XMLStreamSerializer&);
XMLStreamSerializer& operator=(const XMLStreamSerializer&);
void handleError(genxStatus);
void handleError(genxStatus) const;
std::ostream& _outputStream;
std::ostream::iostate _lastStreamState;// Original exception state.
@ -127,6 +183,18 @@ private:
std::size_t _depth;
};
XMLStreamSerializer& operator<< (XMLStreamSerializer&, void (*func) (XMLStreamSerializer&));
/// Stream-like interface for serializer. If the passed argument
/// is a function with the void f(serializer&) signature or is a
/// function object with the void operator() (serializer&) const
/// operator, then this function (object) is called with the passed
/// serializer. Otherwise, the argument is passed to the serializer's
// characters() function.
template <typename T>
XMLStreamSerializer& operator<< (XMLStreamSerializer&, const T& value);
inline void XMLStreamSerializer::startElement(const QName& qname)
{
startElement(qname.namespace_(), qname.name());
@ -137,6 +205,19 @@ inline void XMLStreamSerializer::startElement(const std::string& name)
startElement(std::string(), name);
}
inline void XMLStreamSerializer::endElement (const QName& qname)
{
endElement (qname.namespace_ (), qname.name ());
}
inline void XMLStreamSerializer::endElement (const std::string& name)
{
endElement (std::string (), name);
}
inline void XMLStreamSerializer::element(const std::string& v)
{
if (!v.empty())
@ -193,6 +274,18 @@ inline void XMLStreamSerializer::startAttribute(const std::string& name)
}
inline void XMLStreamSerializer::endAttribute (const QName& qname)
{
endAttribute (qname.namespace_ (), qname.name ());
}
inline void XMLStreamSerializer::endAttribute (const std::string& name)
{
endAttribute (std::string (), name);
}
inline void XMLStreamSerializer::attribute(const QName& qname, const std::string& value)
{
attribute(qname.namespace_(), qname.name(), value);
@ -233,6 +326,62 @@ inline void XMLStreamSerializer::characters(const T& value)
}
// operator<<
//
inline XMLStreamSerializer& operator<< (XMLStreamSerializer& s, void (*func) (XMLStreamSerializer&))
{
func (s);
return s;
}
namespace details
{
// Detect whether T defines void operator(A) const.
//
template <typename T, typename A>
struct is_functor
{
typedef char no[1];
typedef char yes[2];
template <typename X, X> struct check;
template <typename>
static no& test (...);
template <typename X>
static yes& test (check<void (X::*) (A) const, &X::operator ()>*);
static const bool value = sizeof (test<T> (0)) == sizeof (yes);
};
template <typename T, bool = is_functor<T, XMLStreamSerializer&>::value>
struct inserter;
template <typename T>
struct inserter<T, true>
{
static void insert (XMLStreamSerializer& s, const T& f) {f (s);}
};
template <typename T>
struct inserter<T, false>
{
static void insert (XMLStreamSerializer& s, const T& v) {s.characters (v);}
};
}
template <typename T>
inline XMLStreamSerializer& operator<< (XMLStreamSerializer& s, const T& value)
{
details::inserter<T>::insert (s, value);
return s;
}
}
}

@ -117,6 +117,24 @@ void * genxGetUserData(genxWriter w);
genxStatus genxSetPrettyPrint(genxWriter w, int indentation);
int genxGetPrettyPrint(genxWriter w);
/*
* Suspend/resume pretty-printing. Pretty-printing can be suspended
* only inside an element and, unless explicitly resumed, it will
* remain suspended until the end of that element. You should only
* explicitly resume pretty-printing at the element nesting level
* of suspension. If pretty-printing is already suspended at an
* outer nesting level, then subsequent calls to suspend/resume
* are ignored. The PrettyPrintSuspended() function can be used
* to check if pretty-printing is currently suspended. If it is
* not, then this function returns 0. Otherwise, it returns the
* level at which pretty-printing was suspended, with root element
* being level 1.
*/
genxStatus genxSuspendPrettyPrint(genxWriter w);
genxStatus genxResumePrettyPrint(genxWriter w);
int genxPrettyPrintSuspended(genxWriter w);
/*
* Set/get canonicalization. If true, then output explicit closing
* tags and sort attributes. Default is false.
@ -162,7 +180,7 @@ genxNamespace genxDeclareNamespace(genxWriter w,
* If something failed, returns NULL and sets the status code via statusP
*/
genxElement genxDeclareElement(genxWriter w,
genxNamespace ns, constUtf8 type,
genxNamespace ns, constUtf8 name,
genxStatus * statusP);
/*
@ -192,7 +210,7 @@ typedef struct
genxStatus genxStartDocSender(genxWriter w, genxSender * sender);
/*
* End a document. Calls "flush"
* End a document. Calls "flush".
*/
genxStatus genxEndDocument(genxWriter w);
@ -204,6 +222,19 @@ genxStatus genxXmlDeclaration(genxWriter w,
constUtf8 version,
constUtf8 encoding,
constUtf8 standalone);
/*
* Write DOCTYPE declaration. If public_id is not NULL, then this is
* a PUBLIC DOCTYPE declaration, otherwise, if system_id is not NULL,
* then this is a SYSTEM DOCTYPE. If both are NULL, then a DOCTYPE
* that only contains the root element and, if not NULL, internal
* subset is written.
*/
genxStatus genxDoctypeDeclaration(genxWriter w,
constUtf8 root_element,
constUtf8 public_id,
constUtf8 system_id,
constUtf8 internal_subset);
/*
* Write a comment
*/
@ -218,7 +249,7 @@ genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text);
* Start an element
*/
genxStatus genxStartElementLiteral(genxWriter w,
constUtf8 xmlns, constUtf8 type);
constUtf8 xmlns, constUtf8 name);
/*
* Start a predeclared element
@ -226,28 +257,44 @@ genxStatus genxStartElementLiteral(genxWriter w,
*/
genxStatus genxStartElement(genxElement e);
/*
* Get current element. The returned values are valid until this
* element ceases to be current (i.e., EndElement() is called).
* If the element is unqualified, then xmlns is set to NULL.
*/
genxStatus genxGetCurrentElement (genxWriter w,
constUtf8* xmlns, constUtf8* name);
/*
* Write an attribute
*/
genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns,
constUtf8 name, constUtf8 value);
/*
* Write a predeclared attribute
*/
genxStatus genxAddAttribute(genxAttribute a, constUtf8 value);
/*
* Start an attribute
*/
genxStatus genxStartAttributeLiteral(genxWriter w,
constUtf8 xmlns, constUtf8 name);
/*
* Write a predeclared attribute
*/
genxStatus genxAddAttribute(genxAttribute a, constUtf8 value);
/*
* Start a predeclared attribute
*/
genxStatus genxStartAttribute(genxAttribute a);
/*
* Get current attribute. The returned values are valid until this
* attribute ceases to be current (i.e., EndAttribute() is called).
* If the attribute is unqualified, then xmlns is set to NULL.
*/
genxStatus genxGetCurrentAttribute (genxWriter w,
constUtf8* xmlns, constUtf8* name);
/*
* End an attribute
*/

@ -2,4 +2,5 @@ add_subdirectory(DOMParser)
add_subdirectory(DOMWriter)
add_subdirectory(PrettyPrint)
add_subdirectory(SAXParser)
add_subdirectory(RoundTrip)

@ -0,0 +1,7 @@
set(SAMPLE_NAME "RoundTrip")
set(LOCAL_SRCS "")
aux_source_directory(src LOCAL_SRCS)
add_executable( ${SAMPLE_NAME} ${LOCAL_SRCS} )
target_link_libraries( ${SAMPLE_NAME} PocoXML PocoFoundation )

@ -0,0 +1,21 @@
#
# Makefile
#
# $Id: //poco/1.4/XML/samples/SAXParser/Makefile#1 $
#
# Makefile for Poco SAXParser
#
include $(POCO_BASE)/build/rules/global
objects = RoundTrip
target = RoundTrip
target_version = 1
target_libs = PocoXML PocoFoundation
include $(POCO_BASE)/build/rules/exec
ifdef POCO_UNBUNDLED
SYSLIBS += -lexpat
endif

@ -0,0 +1,101 @@
// file : examples/roundtrip/driver.cxx
// copyright : not copyrighted - public domain
#include <string>
#include <fstream>
#include <iostream>
#include "Poco/XML/XMLStreamParser.h"
#include "Poco/XML/XMLStreamSerializer.h"
using namespace std;
using namespace Poco::XML;
int main(int argc, char* argv[])
{
if (argc != 2)
{
cerr << "usage: " << argv[0] << " <xml-file>" << endl;
return 1;
}
try
{
// Enable stream exceptions so that io failures are reported
// as stream rather than as parsing exceptions.
//
ifstream ifs;
ifs.exceptions(ifstream::badbit | ifstream::failbit);
ifs.open(argv[1], ifstream::in | ifstream::binary);
// Configure the parser to receive attributes as events as well
// as to receive prefix-namespace mappings (namespace declarations
// in XML terminology).
//
XMLStreamParser p(ifs, argv[1],
XMLStreamParser::RECEIVE_DEFAULT | XMLStreamParser::RECEIVE_ATTRIBUTES_EVENT | XMLStreamParser::RECEIVE_NAMESPACE_DECLS);
// Configure serializer not to perform indentation. Existing
// indentation, if any, will be preserved.
//
XMLStreamSerializer s(cout, "out", 0);
for (XMLStreamParser::EventType e(p.next()); e != XMLStreamParser::Eof; e = p.next())
{
switch (e)
{
case XMLStreamParser::StartElement:
{
s.startElement(p.getQName());
break;
}
case XMLStreamParser::EndElement:
{
s.endElement();
break;
}
case XMLStreamParser::StartNamespaceDecl:
{
s.namespaceDecl(p.namespace_(), p.prefix());
break;
}
case XMLStreamParser::EndNamespaceDecl:
{
// There is nothing in XML that indicates the end of namespace
// declaration since it is scope-based.
//
break;
}
case XMLStreamParser::StartAttribute:
{
s.startAttribute(p.getQName());
break;
}
case XMLStreamParser::EndAttribute:
{
s.endAttribute();
break;
}
case XMLStreamParser::Characters:
{
s.characters(p.value());
break;
}
case XMLStreamParser::Eof:
{
// Handled in the for loop.
//
break;
}
}
}
} catch (const ios_base::failure&)
{
cerr << "io failure" << endl;
return 1;
} catch (const Poco::Exception& e)
{
cerr << e.displayText() << endl;
return 1;
}
}

@ -105,7 +105,7 @@ XMLStreamSerializer::XMLStreamSerializer(ostream& os, const string& oname, unsig
}
void XMLStreamSerializer::handleError(genxStatus e)
void XMLStreamSerializer::handleError(genxStatus e) const
{
switch (e)
{
@ -153,6 +153,21 @@ void XMLStreamSerializer::endElement()
}
void XMLStreamSerializer::endElement (const string& ns, const string& name)
{
constUtf8 cns, cn;
genxStatus e;
if ((e = genxGetCurrentElement (_writer, &cns, &cn)) ||
reinterpret_cast<const char*> (cn) != name ||
(cns == 0 ? !ns.empty () : reinterpret_cast<const char*> (cns) != ns))
{
handleError (e != GENX_SUCCESS ? e : GENX_SEQUENCE_ERROR);
}
endElement ();
}
void XMLStreamSerializer::element(const string& ns, const string& n, const string& v)
{
startElement(ns, n);
@ -180,6 +195,21 @@ void XMLStreamSerializer::endAttribute()
}
void XMLStreamSerializer::endAttribute (const string& ns, const string& name)
{
constUtf8 cns, cn;
genxStatus e;
if ((e = genxGetCurrentAttribute (_writer, &cns, &cn)) ||
reinterpret_cast<const char*> (cn) != name ||
(cns == 0 ? !ns.empty () : reinterpret_cast<const char*> (cns) != ns))
{
handleError (e != GENX_SUCCESS ? e : GENX_SEQUENCE_ERROR);
}
endAttribute ();
}
void XMLStreamSerializer::attribute(const string& ns, const string& name, const string& value)
{
if (genxStatus e = genxAddAttributeLiteral(_writer, reinterpret_cast<constUtf8>(ns.empty() ? 0 : ns.c_str()), reinterpret_cast<constUtf8>(name.c_str()),
@ -213,7 +243,22 @@ void XMLStreamSerializer::xmlDecl(const string& ver, const string& enc, const st
}
bool XMLStreamSerializer::lookupNamespacePrefix(const string& ns, string& p)
void XMLStreamSerializer::doctypeDecl (const string& re,
const string& pi,
const string& si,
const string& is)
{
if (genxStatus e = genxDoctypeDeclaration (
_writer,
reinterpret_cast<constUtf8> (re.c_str ()),
(pi.empty () ? 0 : reinterpret_cast<constUtf8> (pi.c_str ())),
(si.empty () ? 0 : reinterpret_cast<constUtf8> (si.c_str ())),
(is.empty () ? 0 : reinterpret_cast<constUtf8> (is.c_str ()))))
handleError (e);
}
bool XMLStreamSerializer::lookupNamespacePrefix(const string& ns, string& p) const
{
// Currently Genx will create a namespace mapping if one doesn't
// already exist.
@ -229,5 +274,45 @@ bool XMLStreamSerializer::lookupNamespacePrefix(const string& ns, string& p)
}
QName XMLStreamSerializer::currentElement () const
{
constUtf8 ns, n;
if (genxStatus e = genxGetCurrentElement (_writer, &ns, &n))
handleError (e);
return QName (ns != 0 ? reinterpret_cast<const char*> (ns) : "", reinterpret_cast<const char*> (n));
}
QName XMLStreamSerializer::currentAttribute () const
{
constUtf8 ns, n;
if (genxStatus e = genxGetCurrentAttribute (_writer, &ns, &n))
handleError (e);
return QName (ns != 0 ? reinterpret_cast<const char*> (ns) : "", reinterpret_cast<const char*> (n));
}
void XMLStreamSerializer::suspendIndentation ()
{
if (genxStatus e = genxSuspendPrettyPrint (_writer))
handleError (e);
}
void XMLStreamSerializer::resumeIndentation ()
{
if (genxStatus e = genxResumePrettyPrint (_writer))
handleError (e);
}
size_t XMLStreamSerializer::indentationSuspended () const
{
return static_cast<size_t> (genxPrettyPrintSuspended (_writer));
}
}
}

@ -80,7 +80,7 @@ struct genxNamespace_rec
struct genxElement_rec
{
genxWriter writer;
utf8 type;
utf8 name;
genxNamespace ns;
};
@ -131,6 +131,7 @@ struct genxWriter_rec
/* Pretty-printing state */
int ppIndent;
int ppDepth;
int ppSuspendDepth; /* Non-0 means we are suspended. */
Boolean ppSimple;
/* Canonicalization. */
@ -316,7 +317,7 @@ static genxNamespace findNamespace(plist * pl, constUtf8 uri)
return NULL;
}
static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type)
static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 name)
{
size_t i;
genxElement * ee = (genxElement *) pl->pointers;
@ -325,15 +326,15 @@ static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type)
{
if (xmlns == NULL)
{
if (ee[i]->ns == NULL && strcmp((const char *) type,
(const char *) ee[i]->type) == 0)
if (ee[i]->ns == NULL && strcmp((const char *) name,
(const char *) ee[i]->name) == 0)
return ee[i];
}
else
{
if (ee[i]->ns != NULL &&
strcmp((const char *) xmlns, (const char *) ee[i]->ns->name) == 0 &&
strcmp((const char *) type, (const char *) ee[i]->type) == 0)
strcmp((const char *) name, (const char *) ee[i]->name) == 0)
return ee[i];
}
}
@ -692,6 +693,62 @@ int genxGetPrettyPrint(genxWriter w)
return w->ppIndent;
}
/*
* Suspend/resume pretty-printing.
*/
genxStatus genxSuspendPrettyPrint(genxWriter w)
{
int d = w->ppDepth;
if (w->ppIndent == 0)
return w->status = GENX_SEQUENCE_ERROR;
switch (w->sequence)
{
case SEQUENCE_START_TAG:
case SEQUENCE_ATTRIBUTES:
d++; /* No start tag written, still outer depth. */
case SEQUENCE_CONTENT:
break;
default:
return w->status = GENX_SEQUENCE_ERROR;
}
if (w->ppSuspendDepth == 0) /* Ignore nested suspend/resume calls. */
w->ppSuspendDepth = d;
return w->status;
}
genxStatus genxResumePrettyPrint(genxWriter w)
{
int d = w->ppDepth;
if (w->ppIndent == 0 || w->ppSuspendDepth == 0)
return w->status = GENX_SEQUENCE_ERROR;
switch (w->sequence)
{
case SEQUENCE_START_TAG:
case SEQUENCE_ATTRIBUTES:
d++; /* No start tag written, still outer depth. */
case SEQUENCE_CONTENT:
break;
default:
return w->status = GENX_SEQUENCE_ERROR;
}
if (w->ppSuspendDepth == d) /* Ignore nested suspend/resume calls. */
w->ppSuspendDepth = 0;
return w->status;
}
int genxPrettyPrintSuspended(genxWriter w)
{
return w->ppSuspendDepth;
}
/*
* get/set canonicalization.
*/
@ -752,7 +809,7 @@ void genxDispose(genxWriter w)
for (i = 0; i < w->elements.count; i++)
{
deallocate(w, ee[i]->type);
deallocate(w, ee[i]->name);
deallocate(w, ee[i]);
}
@ -1009,20 +1066,20 @@ utf8 genxGetNamespacePrefix(genxNamespace ns)
* DeclareElement - see genx.h for details
*/
genxElement genxDeclareElement(genxWriter w,
genxNamespace ns, constUtf8 type,
genxNamespace ns, constUtf8 name,
genxStatus * statusP)
{
genxElement old;
genxElement el;
if ((w->status = checkNCName(w, type)) != GENX_SUCCESS)
if ((w->status = checkNCName(w, name)) != GENX_SUCCESS)
{
*statusP = w->status;
return NULL;
}
/* already declared? */
old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, type);
old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, name);
if (old)
return old;
@ -1034,7 +1091,7 @@ genxElement genxDeclareElement(genxWriter w,
el->writer = w;
el->ns = ns;
if ((el->type = copy(w, type)) == NULL)
if ((el->name = copy(w, name)) == NULL)
{
w->status = *statusP = GENX_ALLOC_FAILED;
return NULL;
@ -1217,8 +1274,9 @@ genxStatus genxStartDocSender(genxWriter w, genxSender * sender)
if (w->ppIndent)
{
w->ppSimple = True;
w->ppDepth = 0;
w->ppSuspendDepth = 0;
w->ppSimple = True;
}
return GENX_SUCCESS;
@ -1292,7 +1350,9 @@ static genxStatus writeStartTag(genxWriter w, Boolean close)
if (w->ppIndent)
{
if (w->ppDepth)
if (w->ppDepth &&
/* Suspend depth could be at this element's depth (after ++ below). */
(w->ppSuspendDepth == 0 || w->ppSuspendDepth > w->ppDepth))
if (writeIndentation (w) != GENX_SUCCESS)
return w->status;
@ -1301,6 +1361,15 @@ static genxStatus writeStartTag(genxWriter w, Boolean close)
w->ppDepth++;
w->ppSimple = True;
}
else
{
/*
* Conceptually we incremented/decremented the depth, so check if we
* need to resume pretty-printing.
*/
if (w->ppSuspendDepth > w->ppDepth)
w->ppSuspendDepth = 0;
}
}
SendCheck(w, "<");
@ -1309,7 +1378,7 @@ static genxStatus writeStartTag(genxWriter w, Boolean close)
SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
SendCheck(w, ":");
}
SendCheck(w, e->type);
SendCheck(w, e->name);
/* If we are canonicalizing, then write sorted attributes. Otherwise
write them in the order specified. */
@ -1711,6 +1780,22 @@ genxStatus genxStartAttribute(genxAttribute a)
return GENX_SUCCESS;
}
genxStatus genxGetCurrentAttribute (genxWriter w,
constUtf8* xmlns, constUtf8* name)
{
genxAttribute a;
if (w->sequence != SEQUENCE_START_ATTR)
return w->status = GENX_SEQUENCE_ERROR;
a = w->nowStartingAttr;
*xmlns = a->ns ? a->ns->name : NULL;
*name = a->name;
return GENX_SUCCESS;
}
genxStatus genxEndAttribute(genxWriter w)
{
genxAttribute a;
@ -1744,6 +1829,36 @@ genxStatus genxEndAttribute(genxWriter w)
return GENX_SUCCESS;
}
genxStatus genxGetCurrentElement (genxWriter w,
constUtf8* xmlns, constUtf8* name)
{
int i;
genxElement e;
switch (w->sequence)
{
case SEQUENCE_START_TAG:
case SEQUENCE_ATTRIBUTES:
e = w->nowStarting;
break;
case SEQUENCE_CONTENT:
/* Find the element. The same code as in EndElement() below. */
for (i = (int) (w->stack.count) - 1;
w->stack.pointers[i] != NULL;
i -= 2)
;
e = (genxElement) w->stack.pointers[--i];
break;
default:
return w->status = GENX_SEQUENCE_ERROR;
}
*xmlns = e->ns ? e->ns->name : NULL;
*name = e->name;
return GENX_SUCCESS;
}
genxStatus genxEndElement(genxWriter w)
{
int i;
@ -1789,9 +1904,12 @@ genxStatus genxEndElement(genxWriter w)
{
w->ppDepth--;
if (!w->ppSimple)
if (!w->ppSimple && w->ppSuspendDepth == 0)
if (writeIndentation (w) != GENX_SUCCESS)
return w->status;
if (w->ppSuspendDepth > w->ppDepth)
w->ppSuspendDepth = 0; /* Resume pretty-printing. */
}
SendCheck(w, "</");
@ -1800,11 +1918,15 @@ genxStatus genxEndElement(genxWriter w)
SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
SendCheck(w, ":");
}
SendCheck(w, e->type);
SendCheck(w, e->name);
SendCheck(w, ">");
}
if (w->ppIndent)
/* If this element is written while pretty-printing is suspended,
treat it as simple. As an example, think of an XHTML <b> element
for which we suspend pretty-printing before writing the opening
tag and resume it after the closing one. */
if (w->ppIndent && w->ppSuspendDepth == 0)
w->ppSimple = False;
/*
@ -2143,6 +2265,58 @@ genxStatus genxXmlDeclaration(genxWriter w,
return GENX_SUCCESS;
}
genxStatus genxDoctypeDeclaration(genxWriter w,
constUtf8 re,
constUtf8 pi,
constUtf8 si,
constUtf8 is)
{
if (w->sequence != SEQUENCE_PRE_DOC)
return w->status = GENX_SEQUENCE_ERROR;
if ((w->status = genxCheckText(w, re)) != GENX_SUCCESS)
return w->status;
if (pi != NULL && (w->status = genxCheckText(w, pi)) != GENX_SUCCESS)
return w->status;
if (si != NULL && (w->status = genxCheckText(w, si)) != GENX_SUCCESS)
return w->status;
if (is != NULL && (w->status = genxCheckText(w, is)) != GENX_SUCCESS)
return w->status;
SendCheck (w, "<!DOCTYPE ");
SendCheck (w, re);
if (pi != NULL)
{
SendCheck (w, " PUBLIC\n \"");
SendCheck (w, pi);
SendCheck (w, "\"");
}
if (si != NULL)
{
if (pi == NULL)
SendCheck (w, " SYSTEM");
SendCheck (w, "\n \"");
SendCheck (w, si);
SendCheck (w, "\"");
}
if (is != NULL)
{
SendCheck (w, " [\n");
SendCheck (w, is);
SendCheck (w, "\n]");
}
SendCheck (w, ">\n");
return GENX_SUCCESS;
}
genxStatus genxComment(genxWriter w, constUtf8 text)
{
size_t i;
@ -2251,7 +2425,7 @@ genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text)
* Literal versions of the writing routines
*/
genxStatus genxStartElementLiteral(genxWriter w,
constUtf8 xmlns, constUtf8 type)
constUtf8 xmlns, constUtf8 name)
{
genxNamespace ns = NULL;
genxElement e;
@ -2262,7 +2436,7 @@ genxStatus genxStartElementLiteral(genxWriter w,
if (ns == NULL || w->status != GENX_SUCCESS)
return w->status;
}
e = genxDeclareElement(w, ns, type, &w->status);
e = genxDeclareElement(w, ns, name, &w->status);
if (e == NULL || w->status != GENX_SUCCESS)
return w->status;