45#include <drain/FlexibleVariable.h>
46#include <drain/MapTools.h>
47#include <drain/Sprinter.h>
48#include <drain/StringTools.h>
51#include "ReferenceMap.h"
69class XML :
protected std::map<std::string,FlexibleVariable> {
96 static const intval_t PARENTHESES = 2;
102 static const intval_t UNDEFINED = 0;
107 static const intval_t STYLE_SELECT = 5;
108 static const intval_t JAVASCRIPT = 6;
110 static const intval_t SCOPE_CURLY = SCOPE|CURLY ;
113 typedef std::map<std::string,FlexibleVariable> map_t;
120 static const std::string SCOPE_BEGIN;
121 static const std::string SCOPE_END;
122 static const std::string COMMENT_BEGIN;
123 static const std::string COMMENT_END;
131 const map_t & getMap()
const {
141 NONBREAKABLE_SPACE =
' ',
221 return type != UNDEFINED;
228 template <
class T2,
class ...T3>
230 bool typeIs(
const T2 & arg,
const T3... args)
const {
231 if (type ==
static_cast<intval_t>(arg)){
265 getMap()[
"id"].link(
id);
271 const std::string &
setId(
const std::string & s){
272 getMap()[
"id"].link(
id=s);
277 template <
char C=
'\0',
typename ...TT>
279 const std::string &
setId(
const TT & ...args) {
291 bool isUndefined()
const {
292 return type == UNDEFINED;
296 bool isComment()
const {
297 return type == COMMENT;
301 bool isCText()
const {
302 return type == CTEXT;
306 bool isStyle()
const {
307 return type == STYLE;
318 bool isScript()
const {
319 return type == SCRIPT;
323 bool isScopePlain()
const {
324 return type == SCOPE;
328 bool isScopeJS()
const {
329 return type == SCOPE_CURLY;
333 bool isScope()
const {
334 return isScopePlain() || isScopeJS();
371 template <
class ...T>
381 template <
class ...T>
397 void setText(
const std::string & s);
399 template <
class ...T>
400 void setText(
const T & ...args) {
414 template <
class ...T>
432 template <
class ...T>
435 setText(
'/',
'*',
' ', args...,
' ',
'*',
'/');
440 const std::string & getText()
const {
445 const std::string & getUrl(){
456 getMap()[
"url"].link(url);
461 template <
class ...T>
463 void setName(
const T & ...args){
478 return map_t::empty();
482 bool hasAttribute(
const std::string & key){
483 return MapTools::hasKey(getMap(), key);
487 bool hasUserAttribute(
const std::string & key){
492 const map_t & getAttributes()
const {
498 map_t & getAttributes(){
520 V getAttribute(
const std::string & key,
const V & defaultValue)
const {
527 std::string getAttribute(
const std::string & key,
const char * defaultValue)
const {
544 V getUserAttribute(
const std::string & key,
const V & defaultValue)
const {
549 std::string getUserAttribute(
const std::string & key,
const char *defaultValue)
const {
557 (*this)[key] = value;
564 (*this)[key] = value;
576 template <
class ... TT>
582 template <
class ... TT>
584 void setUserAttribute(
const std::string & key,
const TT &... args){
590 void removeAttribute(
const std::string & s){
591 iterator it = this->find(s);
592 if (it != this->end()){
628 const StyleXML & getStyle()
const {
632 Variable & getStyle(
const std::string & key){
643 T getStyle(
const std::string & key,
const T & defaultValue)
const {
650 void setStyle(
const StyleXML & s){
655 void setStyle(
const std::string & value){
657 if (type == UNDEFINED){
658 mout.reject<LOG_WARNING>(
"setting style for UNDEFINED elem: ", value);
659 mout.unimplemented<LOG_WARNING>(
"future option: set type to STYLE_SELECT");
661 else if (type == STYLE){
662 mout.reject<LOG_WARNING>(
"not setting style for STYLE elem: ", value);
670 void setStyle(
const char *value){
671 setStyle(std::string(value));
675 void setStyle(
const std::string & key,
const std::string & value){
677 if (type == UNDEFINED){
678 mout.reject<LOG_WARNING>(
"setting style for UNDEFINED elem: ", key,
'=', value);
679 mout.unimplemented<LOG_WARNING>(
"future option: set type to STYLE_SELECT");
681 else if (type == STYLE){
682 mout.reject<LOG_WARNING>(
"not setting style for STYLE elem: ", value);
685 this->style[key] = value;
699 void setStyle(
const std::string & key,
const std::initializer_list<V> &l){
705 this->style[key] = l;
728 template <
class ... TT>
730 void setStyle(
const std::string & key,
const TT &... args){
733 drain::Logger(__FILE__, __FUNCTION__).
reject<LOG_WARNING>(
"Setting style of STYLE: ", key,
"=", args...);
742 void setStyle(
const std::initializer_list<std::pair<const char *,const drain::Variable> > &args){
748 void setStyle(
const std::map<std::string, V> & args){
758 ClassListXML classList;
762 const ClassListXML & getClasses()
const {
766 template <
typename ... TT>
768 void addClass(
const TT &... args) {
769 classList.add(args...);
773 void addClass(
const ClassListXML & clist) {
774 for (
auto & cls: clist){
785 return classList.has(cls);
791 void removeClass(
const V & cls) {
792 classList.remove(cls);
802 void specificAttributesToStream(std::ostream & ostr)
const;
805 enum tag_display_mode {
809 EMPTY_TAG = OPENING_TAG | CLOSING_TAG,
816 std::ostream & nodeToStream(std::ostream & ostr, tag_display_mode mode=EMPTY_TAG)
const = 0;
828 std::ostream &
toStream(std::ostream & ostr,
const UnorderedMultiTree<N> & tree,
int indent=0);
832 std::ostream & styleToStream(std::ostream & ostr,
const UnorderedMultiTree<N> & tree,
int indent=0);
836 std::ostream & textToStream(std::ostream & ostr,
const UnorderedMultiTree<N> & tree,
int indent=0);
857 static const std::map<char,char> keyMap = {
866 static const std::map<char,std::string> valueMap = {
867 {entity_t::QUOTE,
"'"},
868 {entity_t::LESS_THAN,
"(("},
869 {entity_t::GREATER_THAN,
"))"},
885 template <
typename N>
892 if (dst.getType() != src.getType()){
895 dst.setType(src.getType());
899 dst.setStyle(src.getStyle());
901 dst.ctext = src.ctext;
930DRAIN_ENUM_DICT(XML::entity_t);
931DRAIN_ENUM_OSTREAM(XML::entity_t)
934std::ostream & XML::textToStream(std::ostream & ostr,
const UnorderedMultiTree<N> & tree,
int indent){
938 std::string fill(2*indent,
' ');
940 typedef UnorderedMultiTree<N> TR;
941 const typename TR::node_data_t & data = tree.data;
946 ostr << fill << data.ctext;
949 if (data.isScopeJS()){
951 if (tree.hasChildren()){
961 for (
const auto & entry: tree.getChildren()){
962 textToStream(ostr, entry.second, indent);
969 if (data.isScopeJS()){
978std::ostream & XML::styleToStream(std::ostream & ostr,
const UnorderedMultiTree<N> & tree,
int indent){
982 std::string fill(2*indent,
' ');
984 typedef UnorderedMultiTree<N> TR;
985 const typename TR::node_data_t & data = tree.data;
987 if (!data.ctext.empty()){
989 ostr << fill << data.ctext;
994 if (!data.getAttributes().empty()){
995 mout.warn(
"STYLE elem ", data.getId(),
" contains attributes, probably meant as style: ", sprinter(data.getAttributes()));
996 ostr <<
"\n\t /" <<
"* <!-- DISCARDED attribs ";
998 ostr <<
" /--> *" <<
"/" <<
'\n';
1001 if (!data.style.empty()){
1005 for (
const auto & attr: data.style){
1006 ostr << fill <<
" ";
1007 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout);
1021 for (
const auto & entry: tree.getChildren()){
1023 if (entry.second->isComment()){
1025 ostr << fill <<
"/* "<< entry.second->ctext <<
" */" <<
'\n';
1030 if (!entry.second->ctext.empty()){
1032 ostr << fill <<
" " << entry.first <<
" {" << entry.second->ctext <<
"} /* CTEXT */ \n";
1035 if (!entry.second->getAttributes().empty()){
1036 ostr << fill <<
" " << entry.first <<
" {\n";
1037 for (
const auto & attr: entry.second->getAttributes()){
1038 ostr << fill <<
" ";
1039 if (attr.first ==
"id"){
1044 ostr << attr.first <<
':' << attr.second <<
';';
1048 ostr << fill <<
" }\n";
1065std::ostream &
XML::toStream(std::ostream & ostr,
const UnorderedMultiTree<N> & tree,
int indent){
1069 typedef UnorderedMultiTree<N> TR;
1071 const typename TR::container_t & children = tree.getChildren();
1074 const typename TR::node_data_t & data = tree.data;
1076 tag_display_mode mode = EMPTY_TAG;
1079 if (data.isCText()){
1080 textToStream(ostr, tree, indent);
1083 else if (data.isScopeJS()){
1085 textToStream(ostr, tree, indent);
1089 else if (data.isCText()){
1097 if (!data.ctext.empty()){
1099 if (data.isSingular()){
1108 if (!children.empty()){
1110 if (data.isSingular()){
1111 mout.
warn(
"Singular (hence normally empty) element <", tree->getTag(),
" id='", data.getId(),
"' ...> has ", children.size(),
" children?");
1116 if (data.isExplicit()){
1119 else if (data.isSingular()){
1130 std::string fill(2*indent,
' ');
1131 if (!data.isScopeJS()){
1138 data.nodeToStream(ostr, mode);
1142 const bool SCRIPT_NONEMPTY = data.isScript() && (tree.hasChildren() || !data.ctext.empty());
1144 if (SCRIPT_NONEMPTY){
1146 ostr <<
"//<![CDATA[\n";
1151 if (mode == EMPTY_TAG){
1158 else if (data.isStyle()){
1160 styleToStream(ostr, tree, indent);
1269 bool ALL_CTEXT =
true;
1271 for (
const auto & entry: children){
1273 if (entry.second.hasChildren() || !entry.second->isCText()){
1282 for (
const auto & entry: children){
1290 if (data.isScript()){
1292 ostr << entry.second->getText();
1302 if (!data.isScopeJS()){
1306 for (
const auto & entry: children){
1308 toStream(ostr, entry.second, indent+1);
1321 if (SCRIPT_NONEMPTY){
1325 std::string fill(2*indent,
' ');
1330 data.nodeToStream(ostr, CLOSING_TAG);
1339#define DRAIN_XML_NODE_SWAP(tree_t) template <> inline void tree_t::swapData(tree_t::node_data_t & node){ this->data.swapXML(node); }
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:326
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:440
Logger & reject(const TT &... args)
Some input has been rejected, for example by a syntax.
Definition Log.h:620
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition Sprinter.h:423
Definition StringBuilder.h:58
const std::string & str() const
For explicit string cast, esp. for (skipping) template deduction.
Definition StringBuilder.h:102
static void commentToStream(std::ostream &ostr, const TT... args)
Practical utility, helps in adding C++ code commenting...
Definition StyleXML.h:99
VariableT is a final class applied through typedefs Variable, Reference and FlexibleVariable.
Definition VariableT.h:87
Base class for XML "nodes", to be data elements T for drain::Tree<T>
Definition XML.h:69
static const std::map< char, std::string > & getEntityMap()
Handy map for converting characters to XML entities. Example: '&' -> "&".
Definition XML.cpp:283
bool typeIs(const T2 &arg, const T3... args) const
Return true, if type is any of the arguments.
Definition XML.h:230
virtual bool isExplicit() const
Tell if this element should always have an explicit closing tag even when empty, like <STYLE></STYLE>
Definition XML.cpp:199
bool typeIsSet() const
Return true, if type is any of the arguments.
Definition XML.h:220
const std::string & setId(const TT &...args)
Concatenates arguments to an id.
Definition XML.h:279
const std::string & setId()
Makes ID a visible attribute.
Definition XML.h:261
static const std::map< char, std::string > & getKeyConversionMap()
Characters that must be avoided in XML attribute keys: space, tab, =.
Definition XML.cpp:114
virtual bool isSingular() const
Tell if this element should always have an explicit closing tag even when empty, like <STYLE></STYLE>
Definition XML.cpp:193
virtual void swapXML(XML &node)
Definition XML.cpp:239
static const std::string USER_ATTR_PREFIX
In XML variants, like SVG, it is possible to use any user defined attributes using prefix "data-" .
Definition XML.h:154
virtual const std::string & getTag() const =0
void setStyle(const std::string &key, const std::initializer_list< V > &l)
Set style of an element.
Definition XML.h:699
const std::string & getId() const
Returns ID of this element. Hopefully a unique ID...
Definition XML.h:286
virtual void setAttribute(const std::string &key, const char *value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition XML.h:563
void setProgramComment(const T &...args)
Sets text surrounded by C language comment marks.
Definition XML.h:434
static const std::map< char, std::string > & getAttributeConversionMap()
Characters that must be avoided in XML attribute values: ".
Definition XML.cpp:129
int intval_t
Definition XML.h:81
void setCommentSafe(const T &...args)
Sets XML style comment <--...--> of concatenated arguments.
Definition XML.h:383
const std::string & setId(const std::string &s)
Makes ID a visible attribute, with a given value.
Definition XML.h:271
void setAttribute(const std::string &key, const TT &... args)
"Final" implementation.
Definition XML.h:578
static const std::map< char, std::string > & getCTextConversionMap()
Characters to avoid in XML free text: <, >, {, },.
Definition XML.cpp:141
static void xmlAttribToStream(std::ostream &ostr, const std::string &key, const V &value)
Handy map for converting characters to XML entities. Example: '&' -> "&".
Definition XML.h:853
void setTextSafe(const T &...args)
Sets slightly converted text, ensuring some XML entities.
Definition XML.h:415
virtual void setAttribute(const std::string &key, const std::string &value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition XML.h:556
static std::ostream & toStream(std::ostream &ostr, const UnorderedMultiTree< N > &tree, int indent=0)
Definition XML.h:1065
void setType(const T &t)
Definition XML.h:200
static N & xmlAssignNode(N &dst, const N &src)
Assign tree node (data) to another.
Definition XML.h:887
void reset()
Keep the element type but clear style, class and string data.
Definition XML.cpp:186
void setStyle(const std::string &key, const TT &... args)
For element/class/id, assign ...
Definition XML.h:730
virtual void setText(const std::string &s)
Assign the text content of this node. If the node type is undefined, set it to CTEXT.
Definition XML.cpp:204
void setComment(const T &...args)
Make this node a comment. Contained tree will not be deleted. In current version, attributes WILL be ...
Definition XML.h:373
XML()
User may optionally filter attributes and CTEST with this using StringTools::replace(XML::encodingMap...
Definition XML.h:173
virtual void setUrl(const std::string &s)
Definition XML.h:453
bool hasClass(const V &cls) const
Definition XML.h:784
VariableT< VariableInitializer< ReferenceT< VariableBase > > > FlexibleVariable
Value container supporting dynamic type with own memory and optional linking (referencing) of externa...
Definition FlexibleVariable.h:66
DRAIN_VARIABLE Variable
Value container supporting dynamic type.
Definition Variable.h:63
Default implementation.
Definition TypeName.h:54