40 #ifndef DRAIN_TREE_XML
41 #define DRAIN_TREE_XML
45 #include "TreeUnordered.h"
56 template <
class T=
int>
57 class NodeXML :
public XML {
62 typedef NodeXML<T> xml_node_t;
65 typedef UnorderedMultiTree<xml_node_t,false, path_t> xml_tree_t;
70 NodeXML(
const intval_t & t = intval_t(0)){
73 drain::StringTools::import(++nextID,
id);
78 NodeXML(
const NodeXML & node){
83 drain::StringTools::import(++nextID,
id);
95 void setType(
const T2 &t){
96 type =
static_cast<intval_t
>(t);
108 const intval_t & getType()
const {
113 T getNativeType()
const {
114 return static_cast<T
>(type);
121 template <
class T2,
class ...T3>
123 bool typeIs(
const T2 & arg,
const T3... args)
const {
124 if (type ==
static_cast<intval_t
>(arg)){
128 return typeIs(args...);
135 bool typeIs()
const {
149 bool isUndefined()
const {
150 return type == UNDEFINED;
158 bool isComment()
const {
159 return type == COMMENT;
164 bool isCText()
const {
165 return type == CTEXT;
170 bool isStyle()
const {
171 return type == STYLE;
178 bool isSelfClosing()
const {
181 const std::set<intval_t> l = {SCRIPT, STYLE};
183 return (l.find(this->getType()) == l.end());
206 const std::string &
getTag(
const T & type){
220 void set(
const NodeXML & node){
223 setType(node.getType());
225 else if (type == STYLE) {
227 mout.suspicious(
"copying STYLE from node: ", node);
229 drain::SmartMapTools::setValues<map_t>(getAttributes(), node.getAttributes());
233 void set(
const intval_t & type){
238 void set(
const std::string & s){
243 void set(
const char *s){
268 void set(
const std::initializer_list<std::pair<const char *,const Variable> > & args){
272 mout.
deprecating(
"Setting attributes/style of a STYLE element.");
282 for (
const auto & entry: args){
283 getAttributes()[entry.first] = entry.second;
292 void set(
const std::map<std::string, V> & args){
296 mout.deprecating(
"Setting attributes/style of a STYLE element: ", args);
306 drain::SmartMapTools::setValues<map_t,true>(getAttributes(), args);
314 void set(
const std::string & key,
const V & value){
318 mout.deprecating(
"Setting style as attributes of a STYLE element: ", key,
':', value);
319 setStyle(key, value);
321 else if (key ==
"style"){
325 mout.unimplemented(
"Setting style as attribute: \"style\"=", value);
328 else if (key ==
"class"){
331 drain::StringTools::import(value, cls);
341 NodeXML & operator=(
const NodeXML & node){
347 NodeXML & operator=(
const xml_tag_t & x){
354 NodeXML & operator=(
const Castable &c){
361 NodeXML & operator=(
const std::string &s){
367 NodeXML & operator=(
const char *s){
373 NodeXML & operator=(
const std::initializer_list<std::pair<const char *,const drain::Variable> > &l){
388 std::ostream &
docToStream(std::ostream & ostr,
const V & tree){
389 V::node_data_t::xml_node_t::docTypeToStream(ostr);
390 V::node_data_t::xml_node_t::toStream(ostr, tree);
397 std::ostream &
toStream(std::ostream &ostr,
const V & t,
const std::string & defaultTag =
"",
int indent=0);
408 for (
const auto & entry: xmldoc_attribs){
409 xmlAttribToStream(ostr, entry.first, entry.second);
429 typedef std::map<xml_tag_t,xml_tag_t> xml_default_elem_map_t;
430 static const xml_default_elem_map_t xml_default_elems;
441 drain::Logger(__FILE__, __FUNCTION__).
reject(
"handleType( ", (
int)type,
" ) - this is available only as specialized, by inherited classed like SVG, HTML?");
451 static xmldoc_attrib_map_t xmldoc_attribs;
473 typedef NodeXML<>::xml_tree_t TreeXML;
477 template <
class E,
bool EX,
class P>
478 struct TypeName<
drain::UnorderedMultiTree<NodeXML<E>,EX,P> > {
480 static const std::string & str(){
521 ostr <<
'<' << getTag() <<
'>' <<
' ';
526 if (!getAttributes().empty()){
530 if (!getClasses().empty()){
537 if (!getStyle().empty()){
544 if (ctext.length() > 20){
545 ostr << ctext.substr(0, 15) <<
"..";
557 std::ostream & operator<<(std::ostream &ostr,
const NodeXML<N> & node){
558 return node.nodeToStream(ostr);
570 std::ostream &
NodeXML<T>::toStream(std::ostream & ostr,
const TR & tree,
const std::string & defaultTag,
int indent){
574 const typename TR::container_t & children = tree.getChildren();
578 std::string fill(2*indent,
' ');
582 if (tree->isComment()){
583 ostr <<
"<!-- " << tree->getTag() <<
' ' << tree->ctext;
585 else if (tree->isCText()){
588 else if (tree->getTag().empty())
589 ostr <<
'<' << defaultTag;
591 ostr <<
'<' << tree->getTag();
597 if (tree->typeIs((intval_t)STYLE)){
599 xmlAttribToStream(ostr,
"data-mode",
"experimental");
603 else if (!tree->isCText()){
605 tree->specificAttributesToStream(ostr);
618 for (
const typename TR::node_data_t::key_t & key: tree->getAttributes().getKeyList()){
619 if (!tree.data[key].empty()){
620 std::stringstream sstr;
621 sstr << tree.data[key];
622 if (!sstr.str().empty()){
623 xmlAttribToStream(ostr, key, sstr.str());
630 if (!tree->style.empty()){
640 if (!tree.data.empty()){
646 if (tree->isComment()){
649 else if (tree->isCText()){
652 else if (tree.data.isSelfClosing() &&
653 (!tree->typeIs((intval_t)STYLE)) && (!tree->typeIs((intval_t)SCRIPT)) &&
654 (children.empty()) && tree->ctext.empty() ){
664 // ... and write contents
667 if (!tree->style.empty()){
668 ostr << "<!-- STYLE? ";
669 drain::Sprinter::toStream(ostr, tree->style.getMap(), drain::Sprinter::xmlAttributeLayout);
674 if (tree->isStyle()){
675 // https://www.w3.org/TR/xml/#sec-cdata-sect
676 // ostr << "<![CDATA[ \n";
678 if (!tree->ctext.empty()){
680 ostr << fill << tree->ctext << " /* CTEXT? */" << '\n
';
683 if (!tree->getAttributes().empty()){
684 drain::Logger mout(__FILE__,__FUNCTION__);
685 mout.warn("STYLE elem ", tree->getId()," contains attributes, probably meant as style: ", sprinter(tree->getAttributes()));
686 ostr << "\n\t /* <!-- DISCARDED attribs ";
687 Sprinter::toStream(ostr, tree->getAttributes()); //, StyleXML::styleRecordLayout
688 ostr << " /--> */" << '\n
';
691 if (!tree->style.empty()){
692 ostr << fill << "/** style obj **/" << '\n
';
693 for (const auto & attr: tree->style){
695 Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
696 //attr.first << ':
' attr.first << ':
';
699 // ostr << fill << "}\n";
700 // Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
705 // ostr << fill << "<!-- elems /-->" << '\n
';
706 ostr << fill << "/* elems */" << '\n
';
707 for (const auto & entry: tree.getChildren()){
708 if (!entry.second->ctext.empty()){
709 //ostr << fill << "<!-- elem("<< entry.first << ") ctext /-->" << '\n
';
710 ostr << fill << " " << entry.first << " {" << entry.second->ctext << "} /* CTEXT */ \n";
712 if (!entry.second->getAttributes().empty()){
713 //ostr << fill << "<!-- elem("<< entry.first << ") attribs /-->" << '\n
';
714 ostr << fill << " " << entry.first << " {\n";
715 for (const auto & attr: entry.second->getAttributes()){
717 ostr << attr.first << ':
' << attr.second << ';
';
718 //Sprinter::pairToStream(ostr, attr, StyleXML::styleLineLayout); // {" :;"}
719 // Sprinter::pairToStream(ostr, attr, StyleXML::styleRecordLayout); // {" :;"}
720 // attr.first << ':
' attr.first << ':
';
723 ostr << fill << " }\n";
724 //Sprinter::sequenceToStream(ostr, entry.second->getAttributes(), StyleXML::styleRecordLayoutActual);
727 // Sprinter::sequenceToStream(ostr, entry.second->style, StyleXML::styleRecordLayout);
729 ostr << "\n"; // end CTEXT
730 //ostr << " ]]>\n"; // end CTEXT
735 if (tree->ctext.empty())
736 ostr << '\n
'; // TODO nextline
741 for (const auto & entry: children){
742 toStream(ostr, entry.second, entry.first, indent+1); // no ++
749 if (tree->typeIs((intval_t)STYLE) || !children.empty()){
751 //std::fill_n(std::ostream_iterator<char>(ostr), 2*indent, ' ');
754 ostr << '<
' << '/
' << tree->getTag() << '>
';
755 ostr << '\n
'; // TODO nextline
757 //if (tree.data.id >= 0)
758 // ostr << "<!-- " << tree.data.id << " /-->\n";
764 const drain::EnumDict<int,XML>::dict_t drain::EnumDict<int,XML>::dict;
767 template <class E, bool EX, class P>
768 std::ostream & operator<<(std::ostream &ostr, const UnorderedMultiTree<NodeXML<E>,EX,P> & tree){
769 // DOC def? TODO: preamble/prologToStream()
770 NodeXML<E>::docTypeToStream(ostr); // must be member, to support virtual?
771 NodeXML<E>::toStream(ostr, tree, "");
776 // CSS element selector.
777 class SelectorXML : public std::string {
782 const char CLASS = '.
';
789 SelectorXML(const std::string &s) : std::string(s){
793 SelectorXML(const char *s) : std::string(s){
796 template <class ...T>
798 SelectorXML(T... args) : std::string(StringBuilder<>(args...)){
803 // CSS class selector.
807 class SelectorXMLcls : public SelectorXML {
812 SelectorXMLcls(const C &cls) : SelectorXML(CLASS, cls){
815 template <class E, class C>
817 SelectorXMLcls(const E &elem, const C &cls) : SelectorXML(elem, CLASS, cls){
822 class SelectorXMLid : public SelectorXML {
827 SelectorXMLid(const T & arg) : SelectorXML(ID, arg){
835 std::ostream & operator<<(std::ostream &ostr, const TreeXML & t){
836 // DOC def? TODO: preamble/prologToStream()
837 TreeXML::node_data_t::docTypeToStream(ostr); // must be member, to support virtual?
838 TreeXML::node_data_t::toStream(ostr, t, "");
846 #endif /* TREEXML_H_ */
Definition: Castable.h:76
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 & deprecating(const TT &... args)
Feature will be removed. Special type of Logger::note().
Definition: Log.h:519
Logger & reject(const TT &... args)
Some input has been rejected, for example by a syntax.
Definition: Log.h:608
Definition: TreeXML.h:341
bool typeIs(const T2 &arg, const T3... args) const
Return true, if type is any of the arguments.
Definition: TreeXML.h:123
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
static std::ostream & toStream(std::ostream &ostr, const V &t, const std::string &defaultTag="", int indent=0)
"Forward definition" of Tree::toOstream
virtual void handleType(const T &type)
Internal function called after setType()
Definition: TreeXML.h:439
std::ostream & nodeToStream(std::ostream &ostr) const
Note: Not designed for XML output, this is more for debugging (in tree dumps),.
Definition: TreeXML.h:518
virtual const std::string & getTag() const
Definition: TreeXML.h:192
std::map< std::string, std::string > xmldoc_attrib_map_t
NOTE: these could/should be templated, in TreeXML<...> right?
Definition: TreeXML.h:450
static const std::string & getTag(const T &type)
Definition: TreeXML.h:206
void set(const std::initializer_list< std::pair< const char *, const Variable > > &args)
Definition: TreeXML.h:268
static std::ostream & docTypeToStream(std::ostream &ostr)
Write the XML definition beginning any XML document.
Definition: TreeXML.h:406
static std::ostream & docToStream(std::ostream &ostr, const V &tree)
Definition: TreeXML.h:733
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
void addClass(const TT &... args)
Style class.
Definition: TreeXML.h:220
static X & xmlAssignNode(X &dst, const X &src)
Assign another tree structure to another.
Definition: XML.h:497
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
Definition: DataSelector.cpp:1277
Wrapper for unique (static) dictionary of enum values.
Definition: EnumFlags.h:66
static const std::string name
Default implementation: name returned by std::type_info::name()
Definition: Type.h:558