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:
parent
ce003c5522
commit
eca1119c82
XML
include/Poco/XML
samples
src
@ -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)
|
||||
|
||||
|
7
XML/samples/RoundTrip/CMakeLists.txt
Normal file
7
XML/samples/RoundTrip/CMakeLists.txt
Normal 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 )
|
21
XML/samples/RoundTrip/Makefile
Normal file
21
XML/samples/RoundTrip/Makefile
Normal 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
|
101
XML/samples/RoundTrip/src/RoundTrip.cpp
Normal file
101
XML/samples/RoundTrip/src/RoundTrip.cpp
Normal 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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
210
XML/src/genx.c
210
XML/src/genx.c
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user