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

View File

@ -55,8 +55,16 @@ public:
void startElement(const QName& qname); void startElement(const QName& qname);
void startElement(const std::string& name); void startElement(const std::string& name);
void startElement(const std::string& ns, const std::string& name); void startElement(const std::string& ns, const std::string& name);
void endElement(); 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 // Helpers for serializing elements with simple content. The first two
// functions assume that startElement() has already been called. The // functions assume that startElement() has already been called. The
// other two serialize the complete element, from start to end. // other two serialize the complete element, from start to end.
@ -79,7 +87,17 @@ public:
void startAttribute(const QName& qname); void startAttribute(const QName& qname);
void startAttribute(const std::string& name); void startAttribute(const std::string& name);
void startAttribute(const std::string& ns, const std::string& name); void startAttribute(const std::string& ns, const std::string& name);
void endAttribute(); 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); void attribute(const QName& qname, const std::string& value);
template<typename T> template<typename T>
void attribute(const QName& qname, const T& value); void attribute(const QName& qname, const T& value);
@ -100,23 +118,61 @@ public:
/// Namespaces declaration. If prefix is empty, then the default /// Namespaces declaration. If prefix is empty, then the default
/// namespace is declared. If both prefix and namespace are empty, /// namespace is declared. If both prefix and namespace are empty,
/// then the default namespace declaration is cleared (xmlns=""). /// 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 = ""); 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, /// XML declaration. If encoding or standalone are not specified,
/// then these attributes are omitted from the output. /// 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. // 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 /// Return true if there is a mapping. In this case, prefix contains
/// the mapped prefix. /// 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: private:
XMLStreamSerializer(const XMLStreamSerializer&); XMLStreamSerializer(const XMLStreamSerializer&);
XMLStreamSerializer& operator=(const XMLStreamSerializer&); XMLStreamSerializer& operator=(const XMLStreamSerializer&);
void handleError(genxStatus); void handleError(genxStatus) const;
std::ostream& _outputStream; std::ostream& _outputStream;
std::ostream::iostate _lastStreamState;// Original exception state. std::ostream::iostate _lastStreamState;// Original exception state.
@ -127,6 +183,18 @@ private:
std::size_t _depth; 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) inline void XMLStreamSerializer::startElement(const QName& qname)
{ {
startElement(qname.namespace_(), qname.name()); startElement(qname.namespace_(), qname.name());
@ -137,6 +205,19 @@ inline void XMLStreamSerializer::startElement(const std::string& name)
startElement(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) inline void XMLStreamSerializer::element(const std::string& v)
{ {
if (!v.empty()) 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) inline void XMLStreamSerializer::attribute(const QName& qname, const std::string& value)
{ {
attribute(qname.namespace_(), qname.name(), 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;
}
} }
} }

View File

@ -117,6 +117,24 @@ void * genxGetUserData(genxWriter w);
genxStatus genxSetPrettyPrint(genxWriter w, int indentation); genxStatus genxSetPrettyPrint(genxWriter w, int indentation);
int genxGetPrettyPrint(genxWriter w); 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 * Set/get canonicalization. If true, then output explicit closing
* tags and sort attributes. Default is false. * 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 * If something failed, returns NULL and sets the status code via statusP
*/ */
genxElement genxDeclareElement(genxWriter w, genxElement genxDeclareElement(genxWriter w,
genxNamespace ns, constUtf8 type, genxNamespace ns, constUtf8 name,
genxStatus * statusP); genxStatus * statusP);
/* /*
@ -192,7 +210,7 @@ typedef struct
genxStatus genxStartDocSender(genxWriter w, genxSender * sender); genxStatus genxStartDocSender(genxWriter w, genxSender * sender);
/* /*
* End a document. Calls "flush" * End a document. Calls "flush".
*/ */
genxStatus genxEndDocument(genxWriter w); genxStatus genxEndDocument(genxWriter w);
@ -204,6 +222,19 @@ genxStatus genxXmlDeclaration(genxWriter w,
constUtf8 version, constUtf8 version,
constUtf8 encoding, constUtf8 encoding,
constUtf8 standalone); 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 * Write a comment
*/ */
@ -218,7 +249,7 @@ genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text);
* Start an element * Start an element
*/ */
genxStatus genxStartElementLiteral(genxWriter w, genxStatus genxStartElementLiteral(genxWriter w,
constUtf8 xmlns, constUtf8 type); constUtf8 xmlns, constUtf8 name);
/* /*
* Start a predeclared element * Start a predeclared element
@ -226,28 +257,44 @@ genxStatus genxStartElementLiteral(genxWriter w,
*/ */
genxStatus genxStartElement(genxElement e); 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 * Write an attribute
*/ */
genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns, genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns,
constUtf8 name, constUtf8 value); constUtf8 name, constUtf8 value);
/*
* Write a predeclared attribute
*/
genxStatus genxAddAttribute(genxAttribute a, constUtf8 value);
/* /*
* Start an attribute * Start an attribute
*/ */
genxStatus genxStartAttributeLiteral(genxWriter w, genxStatus genxStartAttributeLiteral(genxWriter w,
constUtf8 xmlns, constUtf8 name); constUtf8 xmlns, constUtf8 name);
/*
* Write a predeclared attribute
*/
genxStatus genxAddAttribute(genxAttribute a, constUtf8 value);
/* /*
* Start a predeclared attribute * Start a predeclared attribute
*/ */
genxStatus genxStartAttribute(genxAttribute a); 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 * End an attribute
*/ */

View File

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

View File

@ -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 )

View File

@ -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

View File

@ -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;
}
}

View File

@ -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) 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) void XMLStreamSerializer::element(const string& ns, const string& n, const string& v)
{ {
startElement(ns, n); 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) 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()), 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 // Currently Genx will create a namespace mapping if one doesn't
// already exist. // 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));
}
} }
} }

View File

@ -80,7 +80,7 @@ struct genxNamespace_rec
struct genxElement_rec struct genxElement_rec
{ {
genxWriter writer; genxWriter writer;
utf8 type; utf8 name;
genxNamespace ns; genxNamespace ns;
}; };
@ -131,6 +131,7 @@ struct genxWriter_rec
/* Pretty-printing state */ /* Pretty-printing state */
int ppIndent; int ppIndent;
int ppDepth; int ppDepth;
int ppSuspendDepth; /* Non-0 means we are suspended. */
Boolean ppSimple; Boolean ppSimple;
/* Canonicalization. */ /* Canonicalization. */
@ -316,7 +317,7 @@ static genxNamespace findNamespace(plist * pl, constUtf8 uri)
return NULL; return NULL;
} }
static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type) static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 name)
{ {
size_t i; size_t i;
genxElement * ee = (genxElement *) pl->pointers; genxElement * ee = (genxElement *) pl->pointers;
@ -325,15 +326,15 @@ static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type)
{ {
if (xmlns == NULL) if (xmlns == NULL)
{ {
if (ee[i]->ns == NULL && strcmp((const char *) type, if (ee[i]->ns == NULL && strcmp((const char *) name,
(const char *) ee[i]->type) == 0) (const char *) ee[i]->name) == 0)
return ee[i]; return ee[i];
} }
else else
{ {
if (ee[i]->ns != NULL && if (ee[i]->ns != NULL &&
strcmp((const char *) xmlns, (const char *) ee[i]->ns->name) == 0 && 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]; return ee[i];
} }
} }
@ -692,6 +693,62 @@ int genxGetPrettyPrint(genxWriter w)
return w->ppIndent; 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. * get/set canonicalization.
*/ */
@ -752,7 +809,7 @@ void genxDispose(genxWriter w)
for (i = 0; i < w->elements.count; i++) for (i = 0; i < w->elements.count; i++)
{ {
deallocate(w, ee[i]->type); deallocate(w, ee[i]->name);
deallocate(w, ee[i]); deallocate(w, ee[i]);
} }
@ -1009,20 +1066,20 @@ utf8 genxGetNamespacePrefix(genxNamespace ns)
* DeclareElement - see genx.h for details * DeclareElement - see genx.h for details
*/ */
genxElement genxDeclareElement(genxWriter w, genxElement genxDeclareElement(genxWriter w,
genxNamespace ns, constUtf8 type, genxNamespace ns, constUtf8 name,
genxStatus * statusP) genxStatus * statusP)
{ {
genxElement old; genxElement old;
genxElement el; genxElement el;
if ((w->status = checkNCName(w, type)) != GENX_SUCCESS) if ((w->status = checkNCName(w, name)) != GENX_SUCCESS)
{ {
*statusP = w->status; *statusP = w->status;
return NULL; return NULL;
} }
/* already declared? */ /* already declared? */
old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, type); old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, name);
if (old) if (old)
return old; return old;
@ -1034,7 +1091,7 @@ genxElement genxDeclareElement(genxWriter w,
el->writer = w; el->writer = w;
el->ns = ns; el->ns = ns;
if ((el->type = copy(w, type)) == NULL) if ((el->name = copy(w, name)) == NULL)
{ {
w->status = *statusP = GENX_ALLOC_FAILED; w->status = *statusP = GENX_ALLOC_FAILED;
return NULL; return NULL;
@ -1217,8 +1274,9 @@ genxStatus genxStartDocSender(genxWriter w, genxSender * sender)
if (w->ppIndent) if (w->ppIndent)
{ {
w->ppSimple = True;
w->ppDepth = 0; w->ppDepth = 0;
w->ppSuspendDepth = 0;
w->ppSimple = True;
} }
return GENX_SUCCESS; return GENX_SUCCESS;
@ -1292,7 +1350,9 @@ static genxStatus writeStartTag(genxWriter w, Boolean close)
if (w->ppIndent) 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) if (writeIndentation (w) != GENX_SUCCESS)
return w->status; return w->status;
@ -1301,6 +1361,15 @@ static genxStatus writeStartTag(genxWriter w, Boolean close)
w->ppDepth++; w->ppDepth++;
w->ppSimple = True; 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, "<"); SendCheck(w, "<");
@ -1309,7 +1378,7 @@ static genxStatus writeStartTag(genxWriter w, Boolean close)
SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
SendCheck(w, ":"); SendCheck(w, ":");
} }
SendCheck(w, e->type); SendCheck(w, e->name);
/* If we are canonicalizing, then write sorted attributes. Otherwise /* If we are canonicalizing, then write sorted attributes. Otherwise
write them in the order specified. */ write them in the order specified. */
@ -1711,6 +1780,22 @@ genxStatus genxStartAttribute(genxAttribute a)
return GENX_SUCCESS; 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) genxStatus genxEndAttribute(genxWriter w)
{ {
genxAttribute a; genxAttribute a;
@ -1744,6 +1829,36 @@ genxStatus genxEndAttribute(genxWriter w)
return GENX_SUCCESS; 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) genxStatus genxEndElement(genxWriter w)
{ {
int i; int i;
@ -1789,9 +1904,12 @@ genxStatus genxEndElement(genxWriter w)
{ {
w->ppDepth--; w->ppDepth--;
if (!w->ppSimple) if (!w->ppSimple && w->ppSuspendDepth == 0)
if (writeIndentation (w) != GENX_SUCCESS) if (writeIndentation (w) != GENX_SUCCESS)
return w->status; return w->status;
if (w->ppSuspendDepth > w->ppDepth)
w->ppSuspendDepth = 0; /* Resume pretty-printing. */
} }
SendCheck(w, "</"); SendCheck(w, "</");
@ -1800,11 +1918,15 @@ genxStatus genxEndElement(genxWriter w)
SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON); SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
SendCheck(w, ":"); SendCheck(w, ":");
} }
SendCheck(w, e->type); SendCheck(w, e->name);
SendCheck(w, ">"); 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; w->ppSimple = False;
/* /*
@ -2143,6 +2265,58 @@ genxStatus genxXmlDeclaration(genxWriter w,
return GENX_SUCCESS; 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) genxStatus genxComment(genxWriter w, constUtf8 text)
{ {
size_t i; size_t i;
@ -2251,7 +2425,7 @@ genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text)
* Literal versions of the writing routines * Literal versions of the writing routines
*/ */
genxStatus genxStartElementLiteral(genxWriter w, genxStatus genxStartElementLiteral(genxWriter w,
constUtf8 xmlns, constUtf8 type) constUtf8 xmlns, constUtf8 name)
{ {
genxNamespace ns = NULL; genxNamespace ns = NULL;
genxElement e; genxElement e;
@ -2262,7 +2436,7 @@ genxStatus genxStartElementLiteral(genxWriter w,
if (ns == NULL || w->status != GENX_SUCCESS) if (ns == NULL || w->status != GENX_SUCCESS)
return w->status; return w->status;
} }
e = genxDeclareElement(w, ns, type, &w->status); e = genxDeclareElement(w, ns, name, &w->status);
if (e == NULL || w->status != GENX_SUCCESS) if (e == NULL || w->status != GENX_SUCCESS)
return w->status; return w->status;