45 #include <drain/Sprinter.h>
46 #include <drain/FlexibleVariable.h>
48 #include "ReferenceMap.h"
49 #include "TreeUnordered.h"
69 std::ostream & operator<<(std::ostream &ostr,
const StyleXML & style){
82 template <
typename ... TT>
88 template <
typename ... TT>
90 void add(
const std::string & clsName,
const TT &... args) {
91 if (!clsName.empty()){
98 bool has(
const std::string & clsName)
const {
99 return (find(clsName) != end());
103 void remove(
const std::string & clsName) {
104 iterator it = find(clsName);
123 std::ostream & operator<<(std::ostream &ostr,
const ClassListXML & cls){
134 template <
class T=
int>
140 static const int UNDEFINED;
141 static const int COMMENT;
142 static const int CTEXT;
143 static const int STYLE;
144 static const int SCRIPT;
155 typedef UnorderedMultiTree<NodeXML<T>,
false,
path_t> xml_tree_t;
162 drain::StringTools::import(++nextID,
id);
169 drain::StringTools::import(++nextID,
id);
171 type = node.getType();
179 typedef std::map<T,std::string> tag_map_t;
196 return map_t::empty();
200 void setType(
const elem_t &t){
225 const elem_t & getType()
const {
230 bool typeIs(
const elem_t &t)
const {
243 bool isComment()
const {
244 return typeIs((
elem_t)COMMENT);
248 bool isCText()
const {
249 return typeIs((
elem_t)CTEXT);
253 bool isUndefined()
const {
254 return typeIs((
elem_t)UNDEFINED);
261 bool isSelfClosing()
const {
264 const std::set<elem_t> l = {(
elem_t)SCRIPT};
265 return (l.find(this->getType()) == l.end());
272 const std::string & getTag(
unsigned int index){
273 typename tag_map_t::const_iterator it = tags.find((
elem_t)index);
274 if (it != tags.end()){
279 static std::string dummy;
289 const std::string & getTag()
const {
295 const map_t & getAttributes()
const {
301 map_t & getAttributes(){
308 void set(
const NodeXML & node){
311 setType(node.getType());
313 else if (type == STYLE) {
315 mout.suspicious(
"copying STYLE from node: ", node);
317 drain::SmartMapTools::setValues<map_t>(getAttributes(), node.getAttributes());
321 void set(
const elem_t & type){
326 void set(
const std::string & s){
337 void set(
const char *s){
347 void set(
const std::initializer_list<Variable::init_pair_t > &l){
353 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), l);
360 void set(
const std::map<std::string, X> & args){
366 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args);
374 void set(
const std::string & key,
const V & value){
377 setStyle(key, value);
379 else if (key ==
"style"){
383 else if (key ==
"class"){
386 drain::StringTools::import(value, cls);
390 (*this)[key] = value;
396 void remove(
const std::string & s){
398 if (it != this->end()){
419 V get(
const std::string & key,
const V & defaultValue)
const {
424 std::string get(
const std::string & key,
const char * defaultValue)
const {
431 template <
typename ... TT>
434 classList.add(args...);
447 bool hasClass(
const std::string & cls)
const {
448 return classList.has(cls);
452 void removeClass(
const std::string & s) {
464 NodeXML & operator=(
const T & x){
470 NodeXML & operator=(
const Castable &c){
477 NodeXML & operator=(
const std::string &s){
483 NodeXML & operator=(
const char *s){
489 NodeXML & operator=(
const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
506 if ((
int)getType() != COMMENT){
528 drain::StringTools::import(value,
ctext);
543 void setStyle(
const S &value){
548 void setStyle(
const std::string & value){
551 mout.suspicious(
"setting style for undefined elem: ", *
this);
553 else if (type == STYLE){
554 mout.warn(
"setting style for STYLE elem: ", *
this);
559 void setStyle(
const char *value){
560 setStyle(std::string(value));
564 void setStyle(
const std::string & key,
const std::string & value){
565 this->style[key] = value;
571 void setStyle(
const std::string & key,
const V & value){
574 std::stringstream sstr;
576 this->style[key] = value;
579 this->style[key] = value;
591 void setStyle(
const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
606 ClassListXML classList;
608 typedef std::list<path_t> path_list_t;
624 bool findById(
const V & tree,
const std::string & tag,
typename V::path_t & result,
const typename V::path_t & path =
path_t());
664 std::ostream & docToStream(std::ostream & ostr,
const V & tree){
665 V::node_data_t::xml_node_t::docTypeToStream(ostr);
666 V::node_data_t::xml_node_t::toStream(ostr, tree);
673 std::ostream &
toStream(std::ostream &ostr,
const V & t,
const std::string & defaultTag =
"",
int indent=0);
684 for (
const auto & entry: xmldoc_attribs){
685 attribToStream(ostr, entry.first, entry.second);
696 const std::pair<key_t,NodeXML<T> > & entry(){
698 static const std::pair<key_t,NodeXML<T> > nodeEntry(getTag(E), elem);
703 static int getCount(){
730 typedef std::map<std::string,std::string> xmldoc_attrib_map_t;
732 static xmldoc_attrib_map_t xmldoc_attribs;
738 void attribToStream(std::ostream &ostr,
const std::string & key,
const V &value){
739 ostr <<
' ' << key <<
'=' <<
'"' << value <<
'"';
754 const int NodeXML<T>::UNDEFINED(0);
757 const int NodeXML<T>::COMMENT(1);
760 const int NodeXML<T>::CTEXT(2);
763 const int NodeXML<T>::STYLE(3);
766 const int NodeXML<T>::SCRIPT(4);
772 template <
class E,
bool EX,
class P>
775 static const std::string & str(){
780 static const char* get(){
781 return str().c_str();
788 TreeXML & TreeXML::addChild(
const TreeXML::key_t & key);
796 bool NodeXML<N>::findById(
const T & t,
const std::string &
id,
typename T::path_t & result,
const typename T::path_t & path){
804 for (
const auto & entry: t){
805 if (findById(entry.second,
id, result, path_t(path, entry.first))){
842 bool NodeXML<N>::findById(
const T & t,
const std::string &
id, NodeXML<>::path_list_t & result,
const path_t & path){
845 result.push_back(path);
848 for (
const auto & entry: t){
849 findById(entry.second,
id, result, path_t(path, entry.first));
852 return !result.empty();
865 result.push_back(path);
868 for (
const auto & entry: t){
869 findByTag(entry.second, tag, result,
path_t(path, entry.first));
873 return !result.empty();
886 if (tags.count(t->getType()) > 0){
887 result.push_back(path);
890 for (
const auto & entry: t){
891 findByTags(entry.second, tags, result,
path_t(path, entry.first));
895 return !result.empty();
901 bool NodeXML<N>::findByClass(
const T & t,
const std::string & cls, NodeXML<>::path_list_t & result,
const path_t & path){
905 if (t->classList.has(cls)){
906 result.push_back(path);
914 for (
const auto & entry: t){
916 findByClass(entry.second, cls, result, path_t(path, entry.first));
919 return !result.empty();
929 std::ostream & operator<<(std::ostream &ostr,
const NodeXML<N> & node){
932 ostr <<
'<' << node.getTag() <<
'>' <<
' ';
937 if (!node.getAttributes().empty()){
941 if (!node.classList.empty()){
948 if (!node.style.empty()){
953 if (!node.
ctext.empty()){
955 if (node.
ctext.length() > 20){
956 ostr << node.
ctext.substr(0, 15);
975 std::ostream &
NodeXML<N>::toStream(std::ostream & ostr,
const T & tree,
const std::string & defaultTag,
int indent){
978 const typename T::container_t & children = tree.getChildren();
982 std::string fill(2*indent,
' ');
986 if (tree->isComment()){
987 ostr <<
"<!-- " << tree->getTag() <<
' ' << tree->ctext;
989 else if (tree->isCText()){
992 else if (tree->getTag().empty())
993 ostr <<
'<' << defaultTag;
995 ostr <<
'<' << tree->getTag();
1001 if (tree->typeIs((
elem_t)STYLE)){
1003 attribToStream(ostr,
"data-mode",
"experimental");
1007 else if (!tree->isCText()){
1009 if (!tree->classList.empty()){
1010 ostr <<
" class=\"";
1018 for (
const typename T::node_data_t::key_t & key: tree.data.getKeyList()){
1019 if (!tree.data[key].empty()){
1020 std::stringstream sstr;
1021 sstr << tree.data[key];
1022 if (!sstr.str().empty()){
1023 attribToStream(ostr, key, sstr.str());
1030 if (!tree->style.empty()){
1031 ostr <<
" style=\"";
1040 if (!tree.data.empty()){
1046 if (tree->isComment()){
1049 else if (tree->isCText()){
1052 else if (tree.data.isSelfClosing() &&
1053 (!tree->typeIs((
elem_t)STYLE)) && (!tree->typeIs((
elem_t)SCRIPT)) &&
1054 (children.empty()) && tree->ctext.empty() ){
1064 // ... and write contents
1067 if (!tree->style.empty()){
1068 ostr << "<!-- STYLE? ";
1069 drain::Sprinter::toStream(ostr, tree->style.getMap(), drain::Sprinter::xmlAttributeLayout);
1074 if (tree->typeIs((elem_t)STYLE)){
1075 // https://www.w3.org/TR/xml/#sec-cdata-sect
1076 // ostr << "<![CDATA[ \n";
1077 if (!tree->ctext.empty()){
1079 ostr << fill << tree->ctext << '\n
';
1081 if (!tree->getAttributes().empty()){
1082 ostr << "\n\t /* <!-- DISCARDED attribs ";
1083 drain::Logger mout(__FILE__,__FUNCTION__);
1084 mout.warn("STYLE elem contains attributes, probably meant as style: ", tree.data);
1085 Sprinter::toStream(ostr, tree->getAttributes()); //, StyleXML::styleRecordLayout
1086 ostr << " /--> */" << '\n
';
1088 if (!tree->style.empty()){
1089 // ostr << "\n\t<!-- attribs /-->" << '\n
';
1090 //ostr << fill << "<!-- style obj /-->" << '\n
';
1091 ostr << fill << "/** style obj **/" << '\n
';
1093 //Sprinter::sequenceToStream(ostr, tree->style, StyleXML::styleRecordLayout);
1094 for (const auto & attr: tree->style){
1095 ostr << fill << " ";
1096 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
1097 //attr.first << ':
' attr.first << ':
';
1100 // ostr << fill << "}\n";
1101 //Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
1105 // ostr << fill << "<!-- elems /-->" << '\n
';
1106 ostr << fill << "/* elems */" << '\n
';
1107 for (const auto & entry: tree.getChildren()){
1108 if (!entry.second->getAttributes().empty()){
1109 //ostr << fill << "<!-- elem("<< entry.first << ") attribs /-->" << '\n
';
1110 ostr << fill << " " << entry.first << " {\n";
1111 for (const auto & attr: entry.second->getAttributes()){
1112 ostr << fill << " ";
1113 ostr << attr.first << ':
' << attr.second << ';
';
1114 //Sprinter::pairToStream(ostr, attr, StyleXML::styleLineLayout); // {" :;"}
1115 // Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
1116 // attr.first << ':
' attr.first << ':
';
1119 ostr << fill << " }\n";
1120 //Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
1123 if (!entry.second->ctext.empty()){
1124 //ostr << fill << "<!-- elem("<< entry.first << ") ctext /-->" << '\n
';
1125 ostr << fill << " " << entry.first << " {" << entry.second->ctext << "}\n";
1127 // Sprinter::sequenceToStream(ostr, entry.second->style, StyleXML::styleRecordLayout);
1129 ostr << "\n"; // end CTEXT
1130 //ostr << " ]]>\n"; // end CTEXT
1135 if (tree->ctext.empty())
1136 ostr << '\n
'; // TODO nextline
1138 ostr << tree->ctext;
1141 for (const auto & entry: children){
1142 toStream(ostr, entry.second, entry.first, indent+1); // no ++
1149 if (tree->typeIs((elem_t)STYLE) || !children.empty()){
1151 //std::fill_n(std::ostream_iterator<char>(ostr), 2*indent, ' ');
1154 ostr << '<
' << '/
' << tree->getTag() << '>
';
1155 ostr << '\n
'; // TODO nextline
1157 //if (tree.data.id >= 0)
1158 // ostr << "<!-- " << tree.data.id << " /-->\n";
1167 std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
1168 // DOC def? TODO: preamble/prologToStream()
1169 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
1170 TreeXML::node_data_t::toStream(ostr, t, "");
1177 #endif /* TREEXML_H_ */
Definition: Castable.h:76
Container for style classes. Essentially a set of strings, with space-separated output support.
Definition: TreeXML.h:78
static const SprinterLayout layout
Uses spaces as separators.
Definition: TreeXML.h:108
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Definition: TreeXML.h:135
static bool findByTag(const V &tree, const T &tag, path_list_t &result, const path_t &path=path_t())
"Forward definition"
void addClass(const TT &... args)
Style class.
Definition: TreeXML.h:433
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:521
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:502
void setId()
Makes ID a visible attribute.
Definition: TreeXML.h:710
T elem_t
Tag type, CTEXT or COMMENT.
Definition: TreeXML.h:147
static std::ostream & toStream(std::ostream &ostr, const V &t, const std::string &defaultTag="", int indent=0)
"Forward definition" of Tree::toOstream
static bool findByClass(const V &t, const std::string &tag, path_list_t &result, const path_t &path=path_t())
"Forward definition"
const std::string & getId() const
Returns ID of this element. Hopefully a unique ID...
Definition: TreeXML.h:723
static bool findByTags(const V &tree, const std::set< T > &tags, path_list_t &result, const path_t &path=path_t())
"Forward definition"
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition: TreeXML.h:682
static bool findById(const V &tree, const std::string &tag, path_list_t &result, const path_t &path=path_t())
Find all the occurrence of given ID using recursive breath-first search.
std::string ctext
Some general-purpose.
Definition: TreeXML.h:188
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:153
void setId(const std::string &s)
Makes ID a visible attribute, with a given value.
Definition: TreeXML.h:716
A map of references to base type scalars, arrays or std::string; changing values in either are equiva...
Definition: ReferenceMap.h:67
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:82
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
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