55 {
"amp",
'&'}, {
"lt",
'<'}, {
"gt",
'>'},
56 {
"apos",
'\''}, {
"quot",
'"'}, {
"nbsp", 160},
57 {
"iexcl", 161}, {
"cent", 162}, {
"pound", 163},
58 {
"curren", 164}, {
"yen", 165}, {
"brvbar", 166},
59 {
"sect", 167}, {
"uml", 168}, {
"copy", 169},
60 {
"ordf", 170}, {
"laquo", 171}, {
"not", 172},
61 {
"shy", 173}, {
"reg", 174}, {
"macr", 175},
62 {
"deg", 176}, {
"plusmn", 177}, {
"sup2", 178},
63 {
"sup3", 179}, {
"acute", 180}, {
"micro", 181},
64 {
"para", 182}, {
"middot", 183}, {
"cedil", 184},
65 {
"sup1", 185}, {
"ordm", 186}, {
"raquo", 187},
66 {
"frac14", 188}, {
"frac12", 189}, {
"frac34", 190},
75 os << *en.
decl_ << endl;
76 os << spacer << en.
tag_;
79 os <<
"=\"" << *en.
value_ <<
'\"';
85 for (XmlElement::XmlAttrs::iterator itr(en.
attrs_->begin()); itr != en.
attrs_->end(); ++itr)
91 os << itr->first <<
"=\"" << itr->second <<
'"';
102 os << spacer <<
'{' << endl;
105 os << spacer <<
'}' << endl;
115 bool exec_cmd(
const string& cmd,
string& result)
118 FILE *apipe(_popen(cmd.c_str(),
"r"));
120 FILE *apipe(popen(cmd.c_str(),
"r"));
124 const size_t maxcmdresultlen(1024);
125 char buffer[maxcmdresultlen] {};
126 if (!feof(apipe) && fgets(buffer, maxcmdresultlen, apipe) && buffer[0])
129 result.resize(result.size() - 1);
137 return !result.empty();
146 : parent_(parent), root_(parent_ ? parent_->root_ : this), errors_(), line_(1), incline_(1), maxdepth_(),
147 seq_(), value_(), decl_(), depth_(depth), sequence_(++root_->seq_), txtline_(txtline),
148 chldcnt_(), subidx_(subidx), attrs_(), children_(), _was_include(), ordchildren_()
150 istream *ifsptr(&ifs);
154 olb, otag, ocom0, ocom1, comment, ccom0, ccom1, ccomment,
155 oattr, odec, cdec, value, cls, ctag,
156 cdata0, cdata1, cdata2, cdata3, cdata4, cdata5, cdata6, cdata7,
157 vcdata, ecdata0, ecdata1,
162 string tmpotag, tmpctag, tmpval, tmpattr, tmpdec;
167 attrs_ =
new XmlAttrs;
168 attrs_->insert({
"docpath", rootAttr});
171 if (root_->maxdepth_ < depth)
172 root_->maxdepth_ = depth_;
174 while (ifsptr->good() && state != finished)
177 *ifsptr >> noskipws >> c;
181 if (!root_->inclusion_.empty())
200 else if (c ==
'/' && ifsptr->peek() ==
'>')
205 else if (isspace(c) && !tmpotag.empty())
207 else if (c ==
'?' && tmpotag.empty())
209 else if (c ==
'!' && tmpotag.empty())
211 else if (c ==
'=' || c ==
'\\' || c ==
'"' || c ==
'\'')
213 else if (!isspace(c))
216 starttmpotag = root_->line_;
243 decl_ =
new string(tmpdec);
249 if (c ==
'/' && ifsptr->peek() ==
'>')
271 state = depth_ ? finished : olb;
277 state = depth_ ? finished : olb;
387 if (ifsptr->peek() !=
'/')
390 if (depth_ + 1 > MaxDepth)
394 ostr <<
"Error (" << root_->line_ <<
"): maximum depth exceeded (" << MaxDepth <<
')';
401 if (child->GetTag().empty()
402 || (child->_was_include && (!child->children_ || !child->children_->begin()->second->children_)))
411 children_ =
new XmlSubEls;
412 ordchildren_ =
new XmlSet;
415 if (child->_was_include)
417 for (XmlSubEls::const_iterator itr(child->children_->begin()->second->children_->begin());
418 itr != child->children_->begin()->second->children_->end(); ++itr)
420 --itr->second->depth_;
421 children_->insert({itr->first, itr->second});
422 ordchildren_->insert(itr->second);
426 root_->inclusion_.clear();
431 children_->insert({child->GetTag(), child});
432 ordchildren_->insert(child);
451 if (tmpotag != tmpctag)
456 ostr <<
"Error (" << root_->line_ <<
"): unmatched tag " <<
'\''
457 << tmpotag <<
"' (" << starttmpotag <<
") does not close with " <<
'\'' << tmpctag <<
'\'';
458 if (!root_->inclusion_.empty())
459 ostr <<
" in inclusion " << root_->inclusion_ <<
" (" << root_->incline_ <<
')';
464 if ((tag_ = tmpotag) ==
"xi:include")
467 if (rIn_.SearchString(match, tmpattr, 2) == 2)
470 rIn_.SubExpr(match, tmpattr, whatv, 0, 1);
471 ifstream *ifs1(
new ifstream(InplaceXlate(whatv).c_str()));
476 ostr <<
"Error (" << root_->line_ <<
"): could not process include " <<
'\'' << whatv <<
'\'';
483 root_->inclusion_ = whatv;
497 ostr <<
"Error (" << root_->line_ <<
"): invalid xml include specification " <<
'\'' << tmpattr <<
'\'';
503 if (!tmpval.empty() && tmpval.find_first_not_of(
" \t\n\r") != string::npos)
504 value_ =
new string(InplaceXlate(tmpval));
507 else if (!isspace(c))
515 if (!tmpattr.empty())
544 istringstream istr(attlst);
545 enum { ews, tag, es, oq, value, oc0, comment, cc0 } state(ews);
546 string tmptag, tmpval;
552 istr >> noskipws >> c;
569 else if (!isspace(c))
592 else if (c ==
'"' || c ==
'\'')
596 ostr <<
"Error (" <<
root_->
line_ <<
") attribute \'" << tmptag <<
"\' illegal character defined";
607 else if (c ==
'"' || c ==
'\'')
611 if (c ==
'"' || c ==
'\'')
616 else if (!isspace(c))
624 if (tmptag.find_first_of(
"\\\'\"=") != string::npos)
626 if (tmptag !=
"docpath")
630 if (!
attrs_->insert({tmptag, InplaceXlate(tmpval)}).second)
634 ostr <<
"Error (" <<
root_->
line_ <<
") attribute \'" << tmptag <<
"\' already defined";
662 for_each (
children_->begin(),
children_->end(), [](XmlSubEls::value_type& pp) {
delete pp.second; });
669 const string *aval,
const char delim)
const
671 if (what.compare(0, 2,
"//") == 0)
672 return root_->
find(what.substr(2), atag, aval, delim);
674 if (flags_ & nocase ? what % tag_ : what == tag_)
675 return atag && aval && !findAttrByValue(*atag, *aval) ?
nullptr :
this;
680 string::size_type fpos(lwhat.find_first_of(delim));
682 if (fpos != string::npos && lwhat.substr(0, fpos) == tag_)
684 lwhat.erase(0, fpos + 1);
685 fpos = lwhat.find_first_of(delim);
686 const string nwhat(fpos == string::npos ? lwhat : lwhat.substr(0, fpos));
687 pair<XmlSubEls::iterator, XmlSubEls::iterator> result(children_->equal_range(nwhat));
688 while (result.first != result.second)
690 const XmlElement *ptr((*result.first++).second->find(lwhat, atag, aval, delim));
701 int XmlElement::find(
const string& what, XmlSet& eset,
const string *atag,
const string *aval,
702 const char delim)
const
704 if (what.compare(0, 2,
"//") == 0)
705 return root_->
find(what.substr(2), eset, atag, aval, delim);
707 if (flags_ & nocase ? what % tag_ : what == tag_)
709 if (atag && aval && !findAttrByValue(*atag, *aval))
712 return static_cast<int>(eset.size());
718 string::size_type fpos(lwhat.find_first_of(delim));
720 if (fpos != string::npos && lwhat.substr(0, fpos) == tag_)
722 lwhat.erase(0, fpos + 1);
723 fpos = lwhat.find_first_of(delim);
724 const string nwhat(fpos == string::npos ? lwhat : lwhat.substr(0, fpos));
725 pair<XmlSubEls::iterator, XmlSubEls::iterator> result(children_->equal_range(nwhat));
726 while (result.first != result.second)
727 (*result.first++).second->find(lwhat, eset, atag, aval, delim);
728 return static_cast<int>(eset.size());
740 XmlAttrs::iterator itr(
attrs_->find(what));
741 return itr !=
attrs_->end() && itr->second == val;
752 XmlAttrs::iterator itr(
attrs_->find(what));
755 target = itr->second;
779 istringstream istr(whatv);
784 istr >> hex >> value;
787 istr >> dec >> value;
790 oval +=
static_cast<char>(value >> 8 & 0xff);
791 oval +=
static_cast<char>(value & 0xff);
801 const char *gresult(getenv(whatv.c_str()));
804 const string result(gresult);
815 if (exec_cmd(whatv, result))
828 buffer << ifs.rdbuf();
829 return ifs ?
new XmlElement(buffer, 0,
nullptr, 0, 0, docpath) : nullptr;
831 return ifs ?
new XmlElement(ifs, 0,
nullptr, 0, 0, docpath) : nullptr;
838 ifstream ifs(fname.c_str());
839 return Factory(ifs, fname.c_str());
static F8API XmlElement * Factory(std::istream &istr, const char *docpath=nullptr)
F8API int ParseAttrs(const std::string &attlst)
XmlSet * ordchildren_
Set of all child elements in file order.
static std::string & SubExpr(RegMatch &match, const std::string &source, std::string &target, const int offset=0, const int num=0)
POSIX regex wrapper class.
std::map< std::string, std::string > XmlAttrs
F8API bool findAttrByValue(const std::string &what, const std::string &value) const
XmlSubEls * children_
simple n-ary tree
std::map< std::string, unsigned char > Str2Chr
static const Str2Chr stringtochar_
XML entity char lookup.
std::ostream & operator<<(std::ostream &os, const GroupBase &what)
static std::string & Replace(RegMatch &match, std::string &source, const std::string &with, const int num=0)
std::multimap< std::string, XmlElement * > XmlSubEls
F8API bool Insert(XmlElement *what)
A simple xml parser with Xpath style lookup.
virtual F8API ~XmlElement()
Dtor.
std::set< const XmlElement *, EntityOrderComp > XmlSet
static F8API const XmlSet emptyset_
int SearchString(RegMatch &match, const std::string &source, const int subExpr, const int offset=0) const
An invalid configuration parameter was passed.
F8API XmlElement(std::istream &ifs, int subidx, XmlElement *parent=nullptr, int txtline=0, int depth=0, const char *rootAttr=nullptr)
F8API bool GetAttr(const std::string &what, std::string &target) const
F8API const std::string & InplaceXlate(std::string &what)
A class to contain regex matches using RegExp.
const std::string & GetTag() const
F8API const XmlElement * find(const std::string &what, const std::string *atag=nullptr, const std::string *aval=nullptr, const char delim='/') const
static F8API const XmlAttrs emptyattrs_