OmEspHelpers
OmXmlWriter.h
1 /*
2  * OmXmlWriter.h
3  * 2016-11-20
4  *
5  * This class implements an XML writer that produces
6  * more-or-less well-formed XML.
7  *
8  * This code is platform agnostic.
9  *
10  * It has some weakness with regard to escaping special
11  * characters. If you tell it produce an element named named "h1<hahaha>"
12  * it really won't be quoted right. But in basic use it's quite helpful.
13  *
14  * It writes into a character buffer that you provide.
15  *
16  * EXAMPLE
17  *
18  * char myBuffer[1000];
19  * OmXmlWriter w(myBuffer, 1000); // tell it the space limit
20  *
21  * w.beginElement("html");
22  * w.beginElement("head");
23  * w.beginElement("title");
24  * w.addContent("A Web Page");
25  * w.endElement(); // ends title
26  * w.endElement(); // ends head
27  * w.beginElement("body");
28  * w.beginElement("img");
29  * w.addAttribute("src", "http://www.omino.com/img/2016-02-24.jpg");
30  * w.endElement(); // ends img
31  * w.addContent("This is a nice picture");
32  * w.endElement(); // ends body
33  * w.endElement(); // ends html.
34  *
35  * someNetworkThingie.send(w);
36  *
37  * To produce <html><head><title>A Web Page</title></head><body>
38  * <img src="http://www.omino.com/img/2016-02-24.jpg" />
39  * This is a nice picture
40  * </body></html>
41  */
42 
43 #ifndef __OmXmlWriter__
44 #define __OmXmlWriter__
45 
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <stdint.h>
50 
53 {
54 public:
58  virtual bool put(uint8_t ch)
59  {
60  if(this->isDone)
61  return false;
62  printf("%c", ch); // simplest implementation
63  return true; // yup, did.
64  }
65 
66  virtual bool done()
67  {
68  this->isDone = true;
69  return true;
70  }
71 
73  virtual bool putS(const char *s)
74  {
75  bool result = true;
76  while(uint8_t ch = (uint8_t)(*s++))
77  {
78  result &= this->put(ch);
79  }
80  return result;
81  }
82 
83  bool isDone = false;
84 };
85 
90 class OmXmlWriter : public OmIByteStream
91 {
92 public:
93  static const int kOmXmlMaxDepth = 20;
94  OmIByteStream *consumer = 0;
95  int depth = 0;
96  int hasAnything[kOmXmlMaxDepth];
97  const char *elementName[kOmXmlMaxDepth];
98  int position = 0; // index into output
99  bool indenting = false;
100  int errorCount = 0;
101  unsigned int byteCount = 0;
102 
103  const char *attributeName = 0; // current open attribute if any, streaming into it
104 
106  OmXmlWriter(OmIByteStream *consumer);
107 
109  void beginElement(const char *elementName);
110 
112  void beginElement(const char *elementName, const char *attribute1, const char *value1);
113 
115  void addContent(const char *content);
116 
120  void addContentRaw(const char *content);
121 
123  void addContentF(const char *fmt,...);
124 
126  void addAttribute(const char *attribute, const char *value);
127 
129  void addAttributeF(const char *attribute, const char *fmt,...);
130 
132  void addAttributeFBig(int reserve, const char *attribute, const char *fmt,...);
133 
135  void addAttributeUrlF(const char *attribute, const char *fmt,...);
136 
138  void addAttribute(const char *attribute, long long int value);
139 
141  void addElement(const char *elementName);
142 
144  void addElement(const char *elementName, const char *content);
145 
147  void addElementF(const char *elementName, const char *fmt,...);
148 
150  void endElement();
151 
153  void endElement(const char *elementName);
154 
156  void endElements();
157 
161  void addRawContent(const char *rawContent);
162 
164  void setIndenting(int onOff);
165 
167  int getErrorCount();
168 
170  unsigned int getByteCount();
171 
175  bool put(uint8_t ch) override;
176  bool done() override;
177 
178  void beginAttribute(const char *attributeName);
179  void endAttribute();
180 
181  void putf(const char *fmt,...);
182  bool puts(const char *stuff, bool contentEscapes = false);
183 
184 private:
185  void indent();
186  void cr();
187  void addingToElement(bool addContent);
188  bool inElementContentWithEscapes = false; // triggered by addContent, halted by beginElement and endElement. But not inside <script> for example.
189 };
190 
191 #endif /* defined(__OmXmlWriter__) */
OmIByteStream::put
virtual bool put(uint8_t ch)
emit a single byte, overridden by any implementation
Definition: OmXmlWriter.h:58
OmXmlWriter::beginElement
void beginElement(const char *elementName)
Begins a new XML element, like <elementName>
Definition: OmXmlWriter.cpp:92
OmXmlWriter::addElementF
void addElementF(const char *elementName, const char *fmt,...)
Adds an element with content (no need for endElement()) like <h1>Content</h1>
Definition: OmXmlWriter.cpp:345
OmXmlWriter::endElement
void endElement()
Ends the most recent beginElement(). Caps them with either <element/> or </element>.
Definition: OmXmlWriter.cpp:355
OmXmlWriter::addContentRaw
void addContentRaw(const char *content)
Adds text to the document ignoring XML rules But also needed things like rendering DOCTYPE at the sta...
Definition: OmXmlWriter.cpp:220
OmXmlWriter::getByteCount
unsigned int getByteCount()
Bytes written.
Definition: OmXmlWriter.cpp:447
OmXmlWriter
Definition: OmXmlWriter.h:91
OmXmlWriter::put
bool put(uint8_t ch) override
Definition: OmXmlWriter.cpp:452
OmIByteStream::putS
virtual bool putS(const char *s)
convenience routine, same as put byte-by-byte.
Definition: OmXmlWriter.h:73
OmXmlWriter::addAttributeUrlF
void addAttributeUrlF(const char *attribute, const char *fmt,...)
Adds an attribute to an element, using printf semantics, and %20 escapes.
Definition: OmXmlWriter.cpp:311
OmXmlWriter::addAttribute
void addAttribute(const char *attribute, const char *value)
Adds an attribute to an element, like <element attr="value">
Definition: OmXmlWriter.cpp:243
OmIByteStream
Definition: OmXmlWriter.h:53
OmXmlWriter::getErrorCount
int getErrorCount()
Returns nonzero of any errors occurred, usually buffer overruns leading to missing portions.
Definition: OmXmlWriter.cpp:442
OmXmlWriter::addContentF
void addContentF(const char *fmt,...)
Adds text to an element, using printf semantics.
Definition: OmXmlWriter.cpp:225
OmXmlWriter::addElement
void addElement(const char *elementName)
Adds an element with no attributes or content (no need for endElement()) like <hr/>
Definition: OmXmlWriter.cpp:332
OmXmlWriter::addRawContent
void addRawContent(const char *rawContent)
Add content directly to the output stream, no escaping or element balancing. You can definitely break...
Definition: OmXmlWriter.cpp:387
OmXmlWriter::addContent
void addContent(const char *content)
Adds text to an element, like <element>content</element>
Definition: OmXmlWriter.cpp:206
OmXmlWriter::OmXmlWriter
OmXmlWriter(OmIByteStream *consumer)
Instantiate an XML writer to write into the specified buffer.
Definition: OmXmlWriter.cpp:59
OmXmlWriter::addAttributeFBig
void addAttributeFBig(int reserve, const char *attribute, const char *fmt,...)
Handle oversized attribute. :-/.
Definition: OmXmlWriter.cpp:269
OmXmlWriter::addAttributeF
void addAttributeF(const char *attribute, const char *fmt,...)
Adds an attribute to an element, using printf semantics.
Definition: OmXmlWriter.cpp:255
OmXmlWriter::endElements
void endElements()
Ends any remaining elements.
Definition: OmXmlWriter.cpp:381
OmXmlWriter::setIndenting
void setIndenting(int onOff)
Enables primitive formatting. Uses more bytes of buffer.
Definition: OmXmlWriter.cpp:437