nlib
exi/simple2/simple2.cpp

名前空間プレフィックスを保持したりコメントのついたXMLを読み書きするサンプルです。

名前空間つきのXMLを読み書きしています。 名前空間プレフィックス名をバイナリXML内に含めるにはXmlStreamWriterSettingsをデフォルトから変更して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.Init(g_WriterBuf, BUF_SIZE) != 0) 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;
}
class SimplePrinter {
int indent;
XmlStreamReader* r;
ConsoleOutputStream out_;
TextWriter out;
public:
explicit SimplePrinter(XmlStreamReader* reader) : indent(0), r(reader) {
out.Init();
out.Open(&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.Init(g_ReaderBuf, BUF_SIZE) != 0) 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;
}
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