2013-11-06 16:32:29 -05:00
|
|
|
//
|
|
|
|
// FILE: XMLWriter.cpp
|
|
|
|
// AUTHOR: Rob Tillaart
|
2017-12-09 05:58:17 -05:00
|
|
|
// VERSION: 0.1.8
|
2013-11-06 16:32:29 -05:00
|
|
|
// DATE: 2013-11-06
|
|
|
|
// PURPOSE: Simple XML library
|
|
|
|
//
|
|
|
|
// HISTORY:
|
2017-07-16 15:19:50 -04:00
|
|
|
// 0.1.00 2013-11-06 initial version
|
|
|
|
// 0.1.01 2013-11-07 rework interfaces
|
|
|
|
// 0.1.02 2013-11-07 +setIndentSize(), corrected history, +escape support
|
|
|
|
// 0.1.03 2015-03-07 refactored - footprint + interface
|
|
|
|
// 0.1.04 2015-05-21 refactored - reduce RAM -> used F() macro etc.
|
|
|
|
// 0.1.05 2015-05-23 added XMLWRITER_MAXTAGSIZE 15 (to support KML coordinates tag)
|
|
|
|
// 0.1.6 2016-03-16 added incrIndent(), decrIndent(), indent(), raw();
|
2017-07-26 17:20:49 -04:00
|
|
|
// 0.1.7 2017-07-26 added const where possible
|
2017-12-09 05:58:17 -05:00
|
|
|
// 0.1.8 2017-12-09 fix casting issue #83 (long -> int32_t);
|
2013-11-07 14:02:40 -05:00
|
|
|
//
|
2013-11-06 16:32:29 -05:00
|
|
|
// Released to the public domain
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <XMLWriter.h>
|
|
|
|
|
|
|
|
XMLWriter::XMLWriter(Print* stream)
|
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream = stream;
|
|
|
|
reset();
|
2013-11-07 14:02:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void XMLWriter::reset()
|
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_indent = 0;
|
|
|
|
_indentStep = 2;
|
|
|
|
_idx = 0;
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void XMLWriter::header()
|
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->println(F("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"));
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::comment(const char* text, const bool multiLine)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->println();
|
|
|
|
if (!multiLine) indent();
|
|
|
|
_stream->print(F("<!-- "));
|
|
|
|
if (multiLine) _stream->println();
|
|
|
|
_stream->print(text);
|
|
|
|
if (multiLine) _stream->println();
|
|
|
|
_stream->println(F(" -->"));
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagOpen(const char* tag, const bool newline)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagOpen(tag, "", newline);
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagOpen(const char* tag, const char* name, const bool newline)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
// TODO STACK GUARD
|
|
|
|
strncpy(tagStack[_idx++], tag, XMLWRITER_MAXTAGSIZE);
|
|
|
|
tagStart(tag);
|
|
|
|
if (name[0] != 0) tagField("name", name);
|
|
|
|
tagEnd(newline, NOSLASH);
|
|
|
|
_indent += _indentStep;
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagClose(const bool ind)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_indent -= _indentStep;
|
|
|
|
if (ind) indent();
|
|
|
|
_stream->print(F("</"));
|
|
|
|
_stream->print(tagStack[--_idx]);
|
|
|
|
_stream->println(F(">"));
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagStart(const char *tag)
|
2013-11-07 14:02:40 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
indent();
|
|
|
|
_stream->print('<');
|
|
|
|
_stream->print(tag);
|
2013-11-07 14:02:40 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const char* str)
|
2013-11-07 14:02:40 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print(' ');
|
|
|
|
_stream->print(field);
|
|
|
|
_stream->print(F("=\""));
|
2013-11-08 11:13:13 -05:00
|
|
|
#ifdef XMLWRITER_ESCAPE_SUPPORT
|
2017-12-09 05:58:17 -05:00
|
|
|
escape(str);
|
2013-11-08 11:13:13 -05:00
|
|
|
#else
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print(str);
|
2013-11-08 11:13:13 -05:00
|
|
|
#endif
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print('"');
|
2013-11-07 14:02:40 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagEnd(const bool newline, const bool addSlash)
|
2013-11-07 14:02:40 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
if (addSlash) _stream->print('/');
|
|
|
|
_stream->print('>');
|
|
|
|
if (newline) _stream->println();
|
2013-11-07 14:02:40 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const char* str)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagOpen(tag, "", NONEWLINE);
|
2013-11-08 11:13:13 -05:00
|
|
|
#ifdef XMLWRITER_ESCAPE_SUPPORT
|
2017-12-09 05:58:17 -05:00
|
|
|
escape(str);
|
2013-11-08 11:13:13 -05:00
|
|
|
#else
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print(str);
|
2013-11-08 11:13:13 -05:00
|
|
|
#endif
|
2017-12-09 05:58:17 -05:00
|
|
|
tagClose(NOINDENT);
|
2013-11-08 11:13:13 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::setIndentSize(const uint8_t size)
|
2013-11-08 11:13:13 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_indentStep = size;
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const uint8_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagField(field, (uint32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const uint16_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagField(field, (uint32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const uint32_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print(' ');
|
|
|
|
_stream->print(field);
|
|
|
|
_stream->print(F("=\""));
|
|
|
|
_stream->print(value, base);
|
|
|
|
_stream->print('"');
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const int8_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagField(field, (int32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const int16_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagField(field, (int32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const int32_t value, const uint8_t base)
|
2013-11-07 14:02:40 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print(' ');
|
|
|
|
_stream->print(field);
|
|
|
|
_stream->print(F("=\""));
|
|
|
|
_stream->print(value, base);
|
|
|
|
_stream->print('"');
|
2013-11-07 14:02:40 -05:00
|
|
|
}
|
2013-11-06 16:32:29 -05:00
|
|
|
|
2015-03-07 18:11:56 -05:00
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const bool value)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print(' ');
|
|
|
|
_stream->print(field);
|
|
|
|
_stream->print(F("=\""));
|
|
|
|
_stream->print(value?F("true"):F("false"));
|
|
|
|
_stream->print('"');
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::tagField(const char *field, const double value, const uint8_t decimals)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
_stream->print(' ');
|
|
|
|
_stream->print(field);
|
|
|
|
_stream->print(F("=\""));
|
|
|
|
_stream->print(value, decimals);
|
|
|
|
_stream->print('"');
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const uint8_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
writeNode(tag, (uint32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const uint16_t value, const uint8_t base)
|
2013-11-07 14:02:40 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
writeNode(tag, (uint32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const uint32_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagOpen(tag, "", NONEWLINE);
|
|
|
|
_stream->print(value, base); // todo: leading zero's
|
|
|
|
tagClose(NOINDENT);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const int8_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
writeNode(tag, (int32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const int16_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
writeNode(tag, (int32_t) value, base);
|
2015-03-07 18:11:56 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const int32_t value, const uint8_t base)
|
2015-03-07 18:11:56 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagOpen(tag, "", NONEWLINE);
|
|
|
|
_stream->print(value, base); // todo: leading zero's
|
|
|
|
tagClose(NOINDENT);
|
2013-11-07 14:02:40 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const bool value)
|
2013-11-07 14:02:40 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagOpen(tag, "", NONEWLINE);
|
|
|
|
_stream->print(value?F("true"):F("false"));
|
|
|
|
tagClose(NOINDENT);
|
2013-11-07 14:02:40 -05:00
|
|
|
}
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::writeNode(const char* tag, const double value, const uint8_t decimals)
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
tagOpen(tag, "", NONEWLINE);
|
|
|
|
_stream->print(value, decimals);
|
|
|
|
tagClose(NOINDENT);
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
2013-11-07 14:02:40 -05:00
|
|
|
|
2016-04-27 08:14:37 -04:00
|
|
|
void XMLWriter::indent()
|
2013-11-06 16:32:29 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
for (uint8_t i=_indent; i>0; i--) _stream->print(' ');
|
2013-11-06 16:32:29 -05:00
|
|
|
}
|
|
|
|
|
2016-04-27 08:14:37 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-11-08 11:13:13 -05:00
|
|
|
#ifdef XMLWRITER_ESCAPE_SUPPORT
|
2015-05-23 04:24:59 -04:00
|
|
|
char c[6] = "\"\'<>&";
|
2013-11-08 11:13:13 -05:00
|
|
|
char expanded[][7] = { """, "'","<",">","&"}; // todo in flash
|
|
|
|
|
2017-07-26 17:20:49 -04:00
|
|
|
void XMLWriter::escape(const char* str)
|
2013-11-08 11:13:13 -05:00
|
|
|
{
|
2017-12-09 05:58:17 -05:00
|
|
|
char* p = (char *)str;
|
|
|
|
while(*p != 0)
|
|
|
|
{
|
|
|
|
char* q = strchr(c, *p);
|
|
|
|
if (q == NULL) _stream->print(*p);
|
|
|
|
else _stream->print(expanded[q - c]); // uint8_t idx = q-c;
|
|
|
|
p++;
|
|
|
|
}
|
2013-11-08 11:13:13 -05:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-11-06 16:32:29 -05:00
|
|
|
// END OF FILE
|