2013-10-11 21:48:55 +00:00
|
|
|
// g++ -Wall -O2 contrib/html5-printer.cpp -o html5-printer -ltinyxml2
|
|
|
|
|
|
|
|
// This program demonstrates how to use "tinyxml2" to generate conformant HTML5
|
|
|
|
// by deriving from the "tinyxml2::XMLPrinter" class.
|
|
|
|
|
|
|
|
// http://dev.w3.org/html5/markup/syntax.html
|
|
|
|
|
|
|
|
// In HTML5, there are 16 so-called "void" elements. "void elements" NEVER have
|
|
|
|
// inner content (but they MAY have attributes), and are assumed to be self-closing.
|
|
|
|
// An example of a self-closig HTML5 element is "<br/>" (line break)
|
|
|
|
// All other elements are called "non-void" and MUST never self-close.
|
|
|
|
// Examples: "<div class='lolcats'></div>".
|
|
|
|
|
|
|
|
// tinyxml2::XMLPrinter will emit _ALL_ XML elements with no inner content as
|
|
|
|
// self-closing. This behavior produces space-effeceint XML, but incorrect HTML5.
|
|
|
|
|
|
|
|
// Author: Dennis Jenkins, dennis (dot) jenkins (dot) 75 (at) gmail (dot) com.
|
|
|
|
// License: Same as tinyxml2 (zlib)
|
|
|
|
// This example is a small contribution to the world! Enjoy it!
|
|
|
|
|
|
|
|
|
|
|
|
#include <tinyxml2.h>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#if defined (_MSC_VER)
|
|
|
|
#define strcasecmp stricmp
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace tinyxml2;
|
|
|
|
|
|
|
|
// Contrived input containing a mix of void and non-void HTML5 elements.
|
|
|
|
// When printed via XMLPrinter, some non-void elements will self-close (not valid HTML5).
|
|
|
|
static const char input[] =
|
|
|
|
"<html><body><p style='a'></p><br/>©<col a='1' b='2'/><div a='1'></div></body></html>";
|
|
|
|
|
|
|
|
// XMLPrinterHTML5 is small enough, just put the entire implementation inline.
|
|
|
|
class XMLPrinterHTML5 : public XMLPrinter
|
|
|
|
{
|
|
|
|
public:
|
2013-10-11 21:55:14 +00:00
|
|
|
XMLPrinterHTML5 (FILE* file=0, bool compact = false, int depth = 0) :
|
|
|
|
XMLPrinter (file, compact, depth)
|
|
|
|
{}
|
2013-10-11 21:48:55 +00:00
|
|
|
|
|
|
|
protected:
|
2013-10-11 21:55:14 +00:00
|
|
|
virtual void CloseElement () {
|
|
|
|
if (_elementJustOpened && !isVoidElement (_stack.PeekTop())) {
|
|
|
|
SealElement();
|
|
|
|
}
|
|
|
|
XMLPrinter::CloseElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isVoidElement (const char *name) {
|
2013-10-11 21:48:55 +00:00
|
|
|
// Complete list of all HTML5 "void elements",
|
|
|
|
// http://dev.w3.org/html5/markup/syntax.html
|
2013-10-11 21:55:14 +00:00
|
|
|
static const char *list[] = {
|
|
|
|
"area", "base", "br", "col", "command", "embed", "hr", "img",
|
|
|
|
"input", "keygen", "link", "meta", "param", "source", "track", "wbr",
|
|
|
|
NULL
|
|
|
|
};
|
2013-10-11 21:48:55 +00:00
|
|
|
|
|
|
|
// I could use 'bsearch', but I don't have MSVC to test on (it would work with gcc/libc).
|
2013-10-11 21:55:14 +00:00
|
|
|
for (const char **p = list; *p; ++p) {
|
|
|
|
if (!strcasecmp (name, *p)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-11 21:48:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int main (void) {
|
2013-10-11 21:55:14 +00:00
|
|
|
XMLDocument doc (false);
|
|
|
|
doc.Parse (input);
|
2013-10-11 21:48:55 +00:00
|
|
|
|
2013-10-11 21:55:14 +00:00
|
|
|
std::cout << "INPUT:\n" << input << "\n\n";
|
2013-10-11 21:48:55 +00:00
|
|
|
|
2013-10-11 21:55:14 +00:00
|
|
|
XMLPrinter prn (NULL, true);
|
|
|
|
doc.Print (&prn);
|
|
|
|
std::cout << "XMLPrinter (not valid HTML5):\n" << prn.CStr() << "\n\n";
|
2013-10-11 21:48:55 +00:00
|
|
|
|
2013-10-11 21:55:14 +00:00
|
|
|
XMLPrinterHTML5 html5 (NULL, true);
|
|
|
|
doc.Print (&html5);
|
|
|
|
std::cout << "XMLPrinterHTML5:\n" << html5.CStr() << "\n";
|
2013-10-11 21:48:55 +00:00
|
|
|
|
2013-10-11 21:55:14 +00:00
|
|
|
return 0;
|
2013-10-11 21:48:55 +00:00
|
|
|
}
|