45 #include <drain/Sprinter.h>
46 #include <drain/FlexibleVariable.h>
50 #include "ReferenceMap.h"
51 #include "TreeUnordered.h"
75 std::ostream & operator<<(std::ostream &ostr,
const StyleXML & style){
84 static const int UNDEFINED = 0;
85 static const int COMMENT = 1;
86 static const int CTEXT = 2;
87 static const int STYLE = 3;
88 static const int SCRIPT = 4;
104 void attribToStream(std::ostream &ostr,
const std::string & key,
const V &value){
105 ostr <<
' ' << key <<
'=' <<
'"' << value <<
'"';
112 typedef path_t::elem_t path_elem_t;
115 static int getCount(){
134 template <
char C=
'\0',
typename ...TT>
136 void setId(
const TT & ...args) {
148 return map_t::empty();
152 const map_t & getAttributes()
const {
158 map_t & getAttributes(){
167 (*this)[key] = value;
174 (*this)[key] = value;
181 (*this)[key] = value;
186 void remove(
const std::string & s){
188 if (it != this->end()){
207 V get(
const std::string & key,
const V & defaultValue)
const {
212 std::string get(
const std::string & key,
const char * defaultValue)
const {
218 template <
typename ... TT>
221 classList.
add(args...);
239 return classList.has(cls);
243 void removeClass(
const std::string & s) {
255 ClassListXML classList;
257 typedef std::list<path_t> path_list_t;
276 bool findById(
const V & tree,
const std::string & tag,
typename V::path_t & result,
const typename V::path_t & path =
path_t());
296 template <
class V,
class T>
306 template <
class V,
class T>
317 template <
class T2,
class C>
319 bool findByClass(
const T2 & t,
const C & cls, std::list<path_elem_t> & result);
328 template <
class V,
class C>
340 template <
class T=
int>
353 typedef UnorderedMultiTree<NodeXML<T>,
false,
path_t> xml_tree_t;
359 drain::StringTools::import(++nextID,
id);
368 type = node.getType();
369 drain::StringTools::import(++nextID,
id);
378 typedef std::map<T,std::string> tag_map_t;
387 void setType(
const elem_t &t){
399 const elem_t & getType()
const {
404 bool typeIs(
const elem_t &t)
const {
418 bool isComment()
const {
419 return typeIs((
elem_t)COMMENT);
423 bool isCText()
const {
424 return typeIs((
elem_t)CTEXT);
428 bool isUndefined()
const {
429 return typeIs((
elem_t)UNDEFINED);
436 bool isSelfClosing()
const {
439 const std::set<elem_t> l = {(
elem_t)SCRIPT};
440 return (l.find(this->getType()) == l.end());
447 const std::string & getTag(
unsigned int index){
448 typename tag_map_t::const_iterator it = tags.find((
elem_t)index);
449 if (it != tags.end()){
454 static std::string dummy;
464 const std::string & getTag()
const {
473 void set(
const NodeXML & node){
476 setType(node.getType());
478 else if (type == STYLE) {
480 mout.suspicious(
"copying STYLE from node: ", node);
482 drain::SmartMapTools::setValues<map_t>(getAttributes(), node.getAttributes());
486 void set(
const elem_t & type){
491 void set(
const std::string & s){
502 void set(
const char *s){
512 void set(
const std::initializer_list<Variable::init_pair_t > &l){
518 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), l);
525 void set(
const std::map<std::string, X> & args){
531 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args);
539 void set(
const std::string & key,
const V & value){
542 setStyle(key, value);
544 else if (key ==
"style"){
548 else if (key ==
"class"){
551 drain::StringTools::import(value, cls);
564 NodeXML & operator=(
const T & x){
570 NodeXML & operator=(
const Castable &c){
577 NodeXML & operator=(
const std::string &s){
583 NodeXML & operator=(
const char *s){
589 NodeXML & operator=(
const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
604 if ((
int)getType() != COMMENT){
626 else if (typeIs((
elem_t)STYLE)){
631 drain::StringTools::import(value, ctext);
646 void setStyle(
const S &value){
651 void setStyle(
const std::string & value){
654 mout.suspicious(
"setting style for undefined elem: ", *
this);
656 else if (type == STYLE){
657 mout.warn(
"setting style for STYLE elem: ", *
this);
662 void setStyle(
const char *value){
663 setStyle(std::string(value));
667 void setStyle(
const std::string & key,
const std::string & value){
671 this->style[key] = value;
684 void setStyle(
const std::string & key,
const std::initializer_list<V> &l){
691 this->style[key] = l;
701 void setStyle(
const std::string & key,
const V & value){
706 std::stringstream sstr;
709 mout.
warn(
"Check results: skipped ", sstr.str());
710 mout.
warn(
"Check results: applied ", value);
711 this->style[key] = value;
715 this->style[key] = value;
721 void setStyle(
const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
734 V::node_data_t::xml_node_t::docTypeToStream(ostr);
735 V::node_data_t::xml_node_t::toStream(ostr, tree);
742 std::ostream &
toStream(std::ostream &ostr,
const V & t,
const std::string & defaultTag =
"",
int indent=0);
753 for (
const auto & entry: xmldoc_attribs){
754 attribToStream(ostr, entry.first, entry.second);
766 const std::pair<key_t,NodeXML<T> > & entry(){
768 static const std::pair<key_t,NodeXML<T> > nodeEntry(getTag(E), elem);
778 typedef std::map<std::string,std::string> xmldoc_attrib_map_t;
780 static xmldoc_attrib_map_t xmldoc_attribs;
812 typedef drain::UnorderedMultiTree<NodeXML<>,
false, NodeXML<>::path_t> TreeXML;
815 template <
class E,
bool EX,
class P>
818 static const std::string & str(){
823 static const char* get(){
824 return str().c_str();
831 TreeXML & TreeXML::addChild(
const TreeXML::key_t & key);
838 bool XML::findById(
const T & t,
const std::string &
id,
typename T::path_t & result,
const typename T::path_t & path){
846 for (
const auto & entry: t){
847 if (
findById(entry.second,
id, result,
path_t(path, entry.first))){
860 bool XML::findById(
const T & t,
const std::string &
id, NodeXML<>::path_list_t & result,
const path_t & path){
863 result.push_back(path);
866 for (
const auto & entry: t){
870 return !result.empty();
877 template <
class T,
class N>
883 result.push_back(path);
886 for (
const auto & entry: t){
891 return !result.empty();
898 template <
class T,
class N>
904 if (tags.count(t->getType()) > 0){
905 result.push_back(path);
908 for (
const auto & entry: t){
913 return !result.empty();
921 template <
class T2,
class C>
923 bool XML::findByClass(
const T2 & t,
const C & cls, XML::path_list_t & result,
const path_t & path){
927 if (t->classList.has(cls)){
928 result.push_back(path);
931 for (
const auto & entry: t){
936 return !result.empty();
940 template <
class T2,
class C>
943 for (
const auto & entry: t){
944 if (entry.second->hasClass(cls)){
945 result.push_back(entry.first);
949 return !result.empty();
960 std::ostream & operator<<(std::ostream &ostr,
const NodeXML<N> & node){
963 ostr <<
'<' << node.getTag() <<
'>' <<
' ';
968 if (!node.getAttributes().empty()){
972 if (!node.classList.empty()){
979 if (!node.style.empty()){
984 if (!node.ctext.empty()){
986 if (node.ctext.length() > 20){
987 ostr << node.ctext.substr(0, 15);
1006 std::ostream &
NodeXML<N>::toStream(std::ostream & ostr,
const T & tree,
const std::string & defaultTag,
int indent){
1009 const typename T::container_t & children = tree.getChildren();
1013 std::string fill(2*indent,
' ');
1017 if (tree->isComment()){
1018 ostr <<
"<!-- " << tree->getTag() <<
' ' << tree->ctext;
1020 else if (tree->isCText()){
1021 ostr << tree->ctext;
1023 else if (tree->getTag().empty())
1024 ostr <<
'<' << defaultTag;
1026 ostr <<
'<' << tree->getTag();
1032 if (tree->typeIs((
elem_t)STYLE)){
1034 attribToStream(ostr,
"data-mode",
"experimental");
1038 else if (!tree->isCText()){
1040 if (!tree->classList.empty()){
1041 ostr <<
" class=\"";
1049 for (
const typename T::node_data_t::key_t & key: tree.data.getKeyList()){
1050 if (!tree.data[key].empty()){
1051 std::stringstream sstr;
1052 sstr << tree.data[key];
1053 if (!sstr.str().empty()){
1054 attribToStream(ostr, key, sstr.str());
1061 if (!tree->style.empty()){
1062 ostr <<
" style=\"";
1071 if (!tree.data.empty()){
1077 if (tree->isComment()){
1080 else if (tree->isCText()){
1083 else if (tree.data.isSelfClosing() &&
1084 (!tree->typeIs((
elem_t)STYLE)) && (!tree->typeIs((
elem_t)SCRIPT)) &&
1085 (children.empty()) && tree->ctext.empty() ){
1095 // ... and write contents
1098 if (!tree->style.empty()){
1099 ostr << "<!-- STYLE? ";
1100 drain::Sprinter::toStream(ostr, tree->style.getMap(), drain::Sprinter::xmlAttributeLayout);
1105 if (tree->typeIs((elem_t)STYLE)){
1106 // https://www.w3.org/TR/xml/#sec-cdata-sect
1107 // ostr << "<![CDATA[ \n";
1108 if (!tree->ctext.empty()){
1110 ostr << fill << tree->ctext << " /* CTEXT? */" << '\n
';
1112 if (!tree->getAttributes().empty()){
1113 ostr << "\n\t /* <!-- DISCARDED attribs ";
1114 drain::Logger mout(__FILE__,__FUNCTION__);
1115 mout.warn("STYLE elem contains attributes, probably meant as style: ", tree.data);
1116 Sprinter::toStream(ostr, tree->getAttributes()); //, StyleXML::styleRecordLayout
1117 ostr << " /--> */" << '\n
';
1119 if (!tree->style.empty()){
1120 ostr << fill << "/** style obj **/" << '\n
';
1121 for (const auto & attr: tree->style){
1122 ostr << fill << " ";
1123 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
1124 //attr.first << ':
' attr.first << ':
';
1127 // ostr << fill << "}\n";
1128 // Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
1132 // ostr << fill << "<!-- elems /-->" << '\n
';
1133 ostr << fill << "/* elems */" << '\n
';
1134 for (const auto & entry: tree.getChildren()){
1135 if (!entry.second->ctext.empty()){
1136 //ostr << fill << "<!-- elem("<< entry.first << ") ctext /-->" << '\n
';
1137 ostr << fill << " " << entry.first << " {" << entry.second->ctext << "} /* CTEXT */ \n";
1139 if (!entry.second->getAttributes().empty()){
1140 //ostr << fill << "<!-- elem("<< entry.first << ") attribs /-->" << '\n
';
1141 ostr << fill << " " << entry.first << " {\n";
1142 for (const auto & attr: entry.second->getAttributes()){
1143 ostr << fill << " ";
1144 ostr << attr.first << ':
' << attr.second << ';
';
1145 //Sprinter::pairToStream(ostr, attr, StyleXML::styleLineLayout); // {" :;"}
1146 // Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
1147 // attr.first << ':
' attr.first << ':
';
1150 ostr << fill << " }\n";
1151 //Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
1154 // Sprinter::sequenceToStream(ostr, entry.second->style, StyleXML::styleRecordLayout);
1156 ostr << "\n"; // end CTEXT
1157 //ostr << " ]]>\n"; // end CTEXT
1162 if (tree->ctext.empty())
1163 ostr << '\n
'; // TODO nextline
1165 ostr << tree->ctext;
1168 for (const auto & entry: children){
1169 toStream(ostr, entry.second, entry.first, indent+1); // no ++
1176 if (tree->typeIs((elem_t)STYLE) || !children.empty()){
1178 //std::fill_n(std::ostream_iterator<char>(ostr), 2*indent, ' ');
1181 ostr << '<
' << '/
' << tree->getTag() << '>
';
1182 ostr << '\n
'; // TODO nextline
1184 //if (tree.data.id >= 0)
1185 // ostr << "<!-- " << tree.data.id << " /-->\n";
1194 std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
1195 // DOC def? TODO: preamble/prologToStream()
1196 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
1197 TreeXML::node_data_t::toStream(ostr, t, "");
1204 #endif /* TREEXML_H_ */
Definition: Castable.h:76
void add(const std::string &arg, const TT &... args)
Add one or several classes.
Definition: ClassXML.h:72
static const SprinterLayout layout
Uses spaces as separators.
Definition: ClassXML.h:141
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:310
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition: Log.h:428
Definition: TreeXML.h:341
NodeXML & setText(const S &value)
Assign the text content of this node. If the node type is undefined, set it to CTEXT.
Definition: TreeXML.h:619
NodeXML & setComment(const std::string &text="")
Make this node a comment. Contained tree will not be delete. In current version, attributes will be r...
Definition: TreeXML.h:600
void setStyle(const std::string &key, const std::initializer_list< V > &l)
Set style of an element.
Definition: TreeXML.h:684
T elem_t
Tag type, CTEXT or COMMENT.
Definition: TreeXML.h:347
static std::ostream & toStream(std::ostream &ostr, const V &t, const std::string &defaultTag="", int indent=0)
"Forward definition" of Tree::toOstream
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition: TreeXML.h:751
void setStyle(const std::string &key, const V &value)
For element/class/id, assign ...
Definition: TreeXML.h:701
static std::ostream & docToStream(std::ostream &ostr, const V &tree)
Definition: TreeXML.h:733
A map of references to base type scalars, arrays or std::string; changing values in either are equiva...
Definition: ReferenceMap.h:69
void copyStruct(const ReferenceMap2< FlexibleVariable > &m, const T2 &src, T2 &dst, extLinkPolicy policy=RESERVE)
Experimental. Copies references and values of a structure to another.
Definition: ReferenceMap.h:145
@ RESERVE
Definition: ReferenceMap.h:131
ref_t & link(const std::string &key, F &x)
Associates a map entry with a variable.
Definition: ReferenceMap.h:84
map_t::iterator iterator
Needed?
Definition: SmartMap.h:80
std::string get(const std::string &key, const std::string &defaultValue) const
Retrieves a value, or default value if value is unset.
Definition: SmartMap.h:127
const map_t & getMap() const
Definition: SmartMap.h:206
static const SprinterLayout xmlAttributeLayout
Like attributes in XML (HTML, SVG, ...) tags.
Definition: Sprinter.h:227
static std::ostream & sequenceToStream(std::ostream &ostr, const T &x, const SprinterLayout &layout)
Convenience: if sequence type (array, list, set, map) not given, assume array.
Definition: Sprinter.h:321
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition: Sprinter.h:420
Definition: StringBuilder.h:58
VariableT is a final class applied through typedefs Variable, Reference and FlexibleVariable.
Definition: VariableT.h:87
static bool findByClass(const T2 &t, const C &cls, std::list< path_elem_t > &result)
Finds child elements in an XML structure by class name.
Definition: TreeXML.h:941
void addClass(const TT &... args)
Style class.
Definition: TreeXML.h:220
void setId()
Makes ID a visible attribute.
Definition: TreeXML.h:124
virtual void setAttribute(const std::string &key, const char *value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition: TreeXML.h:173
static bool findByClass(const V &t, const C &cls, path_list_t &result, const path_t &path=path_t())
Finds elements recursively in an XML structure by class name supplied as an enumeration type.
virtual void setAttribute(const std::string &key, const std::string &value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition: TreeXML.h:166
const std::string & getId() const
Returns ID of this element. Hopefully a unique ID...
Definition: TreeXML.h:142
static bool findById(const V &tree, const std::string &tag, path_list_t &result, const path_t &path=path_t())
Find the occurrence(s) of given ID using recursive breath-first search.
static bool findByTag(const V &tree, const T &tag, path_list_t &result, const path_t &path=path_t())
static bool findById(const V &tree, const std::string &tag, typename V::path_t &result, const typename V::path_t &path=path_t())
Find the first occurrence of given id using recursive breath-first search.
drain::Path< std::string,'/'> path_t
Tree path type.
Definition: TreeXML.h:111
void setAttribute(const std::string &key, const V &value)
"Final" implementation.
Definition: TreeXML.h:180
static bool findByTags(const V &tree, const std::set< T > &tags, path_list_t &result, const path_t &path=path_t())
"Forward definition"
bool hasClass(const V &cls) const
Definition: TreeXML.h:238
std::string id
Some general-purpose.
Definition: TreeXML.h:95
void setId(const std::string &s)
Makes ID a visible attribute, with a given value.
Definition: TreeXML.h:130
Definition: DataSelector.cpp:1277
Definition: Sprinter.h:137
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition: Type.h:558