nlib
exi/simple2/simple2.cpp

A sample demonstrating reading and writing of XML data that includes namespace prefixes and comments.

It reads and writes XML that includes namespaces. To include the names of the namespace prefixes in the binary XML, you must change the XmlStreamWriterSettings defaults and create a XmlStreamWriter.

#include <string>
using nlib_ns::exi::ExiAllocator;
using nlib_ns::exi::ExiAllocatorEx;
using nlib_ns::exi::XmlStreamReader;
using nlib_ns::exi::XmlStreamReaderSettings;
using nlib_ns::exi::XmlStreamWriter;
using nlib_ns::exi::XmlStreamWriterSettings;
#define N(x) NLIB_EXI_LITERAL(x)
#define M(x) NLIB_EXI_UTF8(x)
// Reads and writes XML in UTF-8 instead of binary if USE_TEXT is defined.
// #define USE_TEXT
const int BUF_SIZE = 1024 * 64;
unsigned char g_ReaderBuf[BUF_SIZE];
unsigned char g_WriterBuf[BUF_SIZE];
const int DATABUF_SIZE = 1024;
unsigned char g_DataBuf[DATABUF_SIZE];
bool WriteXml() {
ExiAllocatorEx al;
if (!al.Initialize(g_WriterBuf, BUF_SIZE)) return false;
MemoryOutputStream os(g_DataBuf, DATABUF_SIZE);
// You can specify encode options via XmlStreamWriterSettings.
XmlStreamWriterSettings settings;
#ifndef USE_TEXT
// '$EXI' will be written in the beginning of the binary if encodeCookie is true.
settings.encodeCookie = true;
// XmlStreamReader can detect encode options specified here if encodeOptions is true.
// You don't have to set XmlStreamReaderSettings when reading.
settings.encodeOptions = true;
// XML comment(<!-- ... -->) is written if preserve.comments is true.
settings.preserve.comments = true;
// User specified names of prefixes are encoded if preserve.prefixes is true.
// Otherwise, the names are defined by system.
settings.preserve.prefixes = true;
#else
// The settings above are not valid if you read XML in text(UTF-8).
settings.processor = nlib_ns::exi::XML_PROCESSOR_TEXT;
#endif
UniquePtr<XmlStreamWriter> w(XmlStreamWriter::Create(&os, settings, al));
if (!w.get()) return false;
// <root>
// <e attr0="value0" attr1="value1" pfx:attr2="value2" xmlns:pfx="http://example.com"/>
// <!--comment-->
// <pfx:e xmlns:pfx="http://example.com">
// <pfx:c/>
// <c/>
// <c xmlns="http://example.com"/>
// <pfx:c xmlns:pfx="http://example.com/2"/>
// </pfx:e>
// <e xmlns="http://example.com/defaultns" att="value">
// <c/>
// <c xmlns=""/>
// </e>
// <pfx:e xmlns:pfx="http://example.com" xmlns:pfx2="http://example.com/2">
// <pfx2:e/>
// </pfx:e>
// </root>
w->WriteStartDocument();
w->WriteStartElement(N("root"));
{
//
// <e attr0="value0" attr1="value1" pfx:attr2="value2" xmlns:pfx="http://example.com"/>
//
w->WriteStartElement(N("e"));
// Omits URI and prefix. no namespace is used.
w->WriteAttribute(N("attr0"), N("value0"));
// Same as the previous one.
w->WriteAttribute(N(""), N(""), N("attr1"), N("value1"));
// Writes the attribute with XML namespace.
w->WriteAttribute(N("pfx"), N("http://example.com"), N("attr2"), N("value2"));
w->WriteEndElement();
}
{
//
// <!--comment-->
//
// You have to enable preserve.comments in XmlStreamWriterSettings
// if you write XML comments.
// Otherwise, no XML comments will be written.
w->WriteComment(N("comment"));
}
{
// <pfx:e xmlns:pfx="http://example.com">
// <pfx:c/>
// <c/>
// <c xmlns="http://example.com"/>
// <pfx:c xmlns:pfx="http://example.com/2"/>
// </pfx:e>
// Automatically generates XML namespace declaration if there is no previous declaration.
w->WriteStartElement(N("pfx"), N("http://example.com"), N("e"));
w->WriteEmptyElement(N("pfx"), N("http://example.com"), N("c"));
// Writes an element with no XML namespace.
w->WriteEmptyElement(N("c"));
// Writes an element with default XML namespace.
w->WriteEmptyElement(N(""), N("http://example.com"), N("c"));
// Overrides the prefix for another URI.
w->WriteEmptyElement(N("pfx"), N("http://example.com/2"), N("c"));
w->WriteEndElement();
}
{
// <e xmlns="http://example.com/defaultns" att="value">
// <c/>
// <c xmlns=""/>
// </e>
// Declares the default namespace if NULL or "" is specified for prefix.
w->WriteStartElement(N(""), N("http://example.com/defaultns"), N("e"));
// Default XML namespace is not valid on attributes.
// The attribute without XML namespace is written.
w->WriteAttribute(N("att"), N("value"));
// Writes the element with default XML namespace.
w->WriteEmptyElement(N(""), N("http://example.com/defaultns"), N("c"));
// Resets the default XML namespace, and the elements with no XML namespace is written.
w->WriteEmptyElement(N("c"));
w->WriteEndElement();
}
{
// <pfx:e xmlns:pfx="http://example.com" xmlns:pfx2="http://example.com/2">
// <pfx2:e/>
// </pfx:e>
w->WriteStartElement(N("pfx"), N("http://example.com"), N("e"));
// You can also declare an XML namespace by WriteNamespace().
w->WriteNamespace(N("pfx2"), N("http://example.com/2"));
// XML namespace declaration is not performed
// because the same XML namespace is declared at the parent element.
w->WriteEmptyElement(N("pfx2"), N("http://example.com/2"), N("e"));
w->WriteEndElement();
}
w->WriteEndElement();
w->WriteEndDocument();
w->Close();
return w->IsOk();
}
class SimplePrinter {
int indent;
XmlStreamReader* r;
ConsoleOutputStream out_;
TextWriter out;
public:
explicit SimplePrinter(XmlStreamReader* reader) : indent(0), r(reader) { out.Init(&out_); }
void Indent() {
for (int i = 0; i < indent; ++i) {
out.Write(" ");
}
}
void Print();
};
void SimplePrinter::Print() {
// Prints XML like tagged text.
while (r->HasNext()) {
switch (r->Next()) {
case XmlStreamReader::START_ELEMENT: {
const ExiChar* prefix;
const ExiChar* uri;
Indent();
// URIs for local names are also written.
prefix = r->GetPrefix();
uri = r->GetNamespaceUri();
if (uri[0] == '\0')
out.WriteFormat("<%s", M(r->GetLocalName()));
else
out.WriteFormat("<%s(%s):%s", M(prefix), M(r->GetNamespaceUri()),
M(r->GetLocalName()));
// Outputs XML namespace declaration
{
// numNs >= 1 if XML namespaces are declared.
size_t numNs = r->GetNamespaceCount();
size_t i;
for (i = 0; i < numNs; ++i) {
prefix = r->GetNamespacePrefix(i);
if (prefix[0] == '\0') {
// Default XML namespace. prefix is empty string.
out.WriteFormat(" xmlns=\"%s\"", M(r->GetNamespaceUri(i)));
} else {
out.WriteFormat(" xmlns:%s=\"%s\"", M(prefix), M(r->GetNamespaceUri(i)));
}
}
}
// Outputs XML attributes
{
size_t numAtt = r->GetAttributeCount();
size_t i;
for (i = 0; i < numAtt; ++i) {
// Note that the order of the attributes is arbitrary in XML.
prefix = r->GetAttributePrefix(i);
uri = r->GetAttributeNamespaceUri(i);
if (uri[0] == '\0') {
out.WriteFormat(" %s=\"%s\"", M(r->GetAttributeLocalName(i)),
M(r->GetAttributeValue(i)));
} else {
out.WriteFormat(" %s(%s):%s=\"%s\"", M(prefix), M(uri),
M(r->GetAttributeLocalName(i)), M(r->GetAttributeValue(i)));
}
}
}
out.Write(">\n");
++indent;
} break;
case XmlStreamReader::END_ELEMENT: {
const ExiChar* prefix;
--indent;
Indent();
prefix = r->GetPrefix();
if (prefix[0] == '\0') {
out.WriteFormat("</%s>\n", M(r->GetLocalName()));
} else {
out.WriteFormat("</%s:%s>\n", M(prefix), M(r->GetLocalName()));
}
} break;
case XmlStreamReader::COMMENT:
Indent();
// In the case of XML comment,
// the string returned by r->GetText() becomes invalid after r->Next() is called.
// You have to copy the string if you use later.
out.WriteFormat("<!--%s-->\n", M(r->GetText()));
break;
default:
break;
}
}
}
bool ReadXml() {
ExiAllocatorEx al;
if (!al.Initialize(g_ReaderBuf, BUF_SIZE)) return false;
MemoryInputStream is(g_DataBuf, DATABUF_SIZE);
XmlStreamReaderSettings settings;
#ifndef USE_TEXT
// The settings in the binary XML is used if encodeOption is true in it.
// Reads XML comments enabled binary if preserve.comments is true.
// settings.preserve.comments = true;
// Reads prefix encoding enabled binary if preserve.prefixes is true.
// settings.preserve.prefixes = true;
#else
settings.processor = nlib_ns::exi::XML_PROCESSOR_TEXT;
#endif
UniquePtr<XmlStreamReader> r(XmlStreamReader::Create(&is, settings, al));
if (!r.get()) return false;
SimplePrinter printer(r.get());
printer.Print();
return r->IsOk();
}
bool SampleMain(int, char**) {
// no global allocator used in this sample
NLIB_ASSERT(!ExiAllocator::GetAllocator());
nlib_printf("Write and Read an XML with xmlnamespace\n\n");
bool result = WriteXml() && ReadXml();
// no global allocator used in this sample
NLIB_ASSERT(!ExiAllocator::GetAllocator());
return result;
}
NLIB_MAINFUNC