#include #include #include #include #include "xml.h" /////////////////////////////////////////////////////////// // Utilities /////////////////////////////////////////////////////////// void Spaces(ostream& outf, int nSpaces) { outf << '\n'; if (nSpaces > 0) { TString str(nSpaces, ' '); str.print_on(outf); } } int hex2int(const char* str) { int n = 0; for (int i = 0; str[i]; i++) { if (str[i] >= '0' && str[i] <= '9') { n *= 16; n += str[i]-'0'; } else if (str[i] >= 'A' && str[i] <= 'F') { n *= 16; n += str[i]-'A'+10; } else break; } return n; } const TString& EscapeSequence(char cStart, istream& inf) { TString& str = get_tmp_string(); if (cStart == '&') { for (char c = inf.get(); c != ';'; c = inf.get()) str << c; if (str[0] == '#') { char c = hex2int(str); str = c; } if (str == "lt") return str ="<"; if (str == "gt") return str =">"; if (str == "nbsp") return str =" "; if (str == "Agrave") return str ="À"; if (str == "Egrave") return str ="È"; if (str == "Eacuto") return str ="É"; if (str == "Igrave") return str ="Ì"; if (str == "Ograve") return str ="Ò"; if (str == "Ugrave") return str ="Ù"; if (str == "agrave") return str ="à"; if (str == "egrave") return str ="è"; if (str == "eacuto") return str ="é"; if (str == "igrave") return str ="ì"; if (str == "ograve") return str ="ò"; if (str == "ugrave") return str ="ù"; const char tmp[2] = { cStart, '\0' }; str.insert(tmp); } else if (cStart == '%') { for (int i = 0; i < 2; i++) str << inf.get(); char c = hex2int(str); str = c; } return str; } void WriteXmlString(ostream& outf, const char* str) { for (int i = 0; str[i]; i++) { char c = str[i]; if (c < 0 || strchr("<>/&", c) != NULL) { unsigned int n = (unsigned char)c; TString8 tmp; tmp.format("%%%02X", n); tmp.print_on(outf); } else outf << c; } } /////////////////////////////////////////////////////////// // TXmlAttr /////////////////////////////////////////////////////////// class TXmlAttr : public TString { public: void Write(ostream& outf) const; TXmlAttr(const char* str) : TString(str) { } }; void TXmlAttr::Write(ostream& outf) const { if (empty()) { outf << '"' << '"'; } else { if (isdigit((*this)[0])) { print_on(outf); } else { outf << '"'; print_on(outf); outf << '"'; } } } /////////////////////////////////////////////////////////// // TXmlItem /////////////////////////////////////////////////////////// TXmlItem& TXmlItem::SetAttr(const char* strAttr, const char* strVal) { if (m_Attributes == NULL) m_Attributes = new TAssoc_array; m_Attributes->remove(strAttr); m_Attributes->add(strAttr, new TXmlAttr(strVal)); return *this; } const TString& TXmlItem::GetAttr(const char* strAttr) const { if (m_Attributes != NULL) { const TXmlAttr* str = (const TXmlAttr*)m_Attributes->objptr(strAttr); if (str != NULL) return *str; } return EMPTY_STRING; } int TXmlItem::GetIntAttr(const char* strAttr) const { return atoi(GetAttr(strAttr)); } int TXmlItem::GetChildren() const { int n = 0; if (m_Children != NULL) n = m_Children->items(); return n; } TXmlItem* TXmlItem::GetChild(size_t n) const { TXmlItem* i = NULL; if (m_Children != NULL) i = (TXmlItem*)m_Children->objptr(n); return i; } // 0 = Nulla; 1 = Simbolo terminale; 2 = Stringa tra apici; 3 = parola qualsiasi int TXmlItem::GetWord(istream& inf, TString& str) const { str.cut(0); int cFirstChar = EOF; while (!inf.eof()) { cFirstChar = inf.get(); if (cFirstChar <= 0 || cFirstChar > ' ') break; } if (cFirstChar == EOF) return 0; const bool bIsString = cFirstChar == '"' || cFirstChar == '\''; if (!bIsString) { str << char(cFirstChar); if (strchr("<=/>", cFirstChar) != NULL) return 1; // Simboli terminali } while (!inf.eof()) { int c = inf.get(); if (bIsString) { if (c == cFirstChar) break; if (c >= '\0' && c <= ' ') c = ' '; str << char(c); } else { if (c >= '\0' && c <= ' ') break; if (strchr("<=/>", c)) { inf.putback(char(c)); break; } str << char(c); } } return bIsString ? 2 : 3; } int TXmlItem::ReadTag(istream& inf) { TString str; const int tt = GetWord(inf, str); if (tt == 0) return -1; if (tt >= 2) // sequence of words (2 or 3) { if (tt == 2) { str.insert("\""); str << '"'; } bool bFirstChar = true; while (!inf.eof()) { char c = inf.get(); if (c == '<') { inf.putback(c); break; } if (bFirstChar) { str << ' '; bFirstChar = false; } if (c == '&' || c == '#' || c == '%') str << EscapeSequence(c, inf); else str << c; } SetTag(""); SetText(str); return 0; } TString name, tmp; bool bChildrenFollow = true; GetWord(inf, m_strTag); if (m_strTag == "/") // Sto leggendo un tag di chiusura del tipo { bChildrenFollow = false; GetWord(inf, tmp); m_strTag << tmp; } while (GetWord(inf, name)) { if (name[0] == '>') return bChildrenFollow ? +1 : 0; if (name[0] == '/') { bChildrenFollow = false; continue; } // Ho letto un nome di attributo GetWord(inf, tmp); if (tmp.empty() || tmp[0] != '=') break; // Leggo il valore dell'attributo GetWord(inf, tmp); SetAttr(name, tmp); } return -1; } TXmlItem& TXmlItem::AddChild(TXmlItem* pItem) { if (m_Children == NULL) m_Children = new TArray; if (pItem == NULL) pItem = new TXmlItem; m_Children->add(pItem); return *pItem; } TXmlItem& TXmlItem::AddChild(const char* strTagName) { TXmlItem& i = AddChild((TXmlItem*)NULL); i.SetTag(strTagName); return i; } TXmlItem& TXmlItem::AddSoapString(const char* name, const char* value, bool typized) { TXmlItem& xmlVar = AddChild(name); if (typized) xmlVar.SetAttr("xsi:type", "xsd:string"); xmlVar.AddChild("").SetText(value); return xmlVar; } TXmlItem& TXmlItem::AddSoapInt(const char* name, int value, bool typized) { TXmlItem& xmlVar = AddChild(name); if (typized) xmlVar.SetAttr("xsi:type", "xsd:int"); TString16 str; str << value; xmlVar.AddChild("").SetText(str); return xmlVar; } void TXmlItem::RemoveLastChild() { if (m_Children != NULL) m_Children->destroy(m_Children->last()); } bool TXmlItem::Read(istream& inf) { Destroy(); const int res = ReadTag(inf); if (res > 0) // There are children ahead { while (!inf.eof()) { TXmlItem& item = AddChild("/"); // Add dummy child if (item.Read(inf)) { if (item.m_strTag[0] == '/') break; } else break; } RemoveLastChild(); // Remove dummy child } return res >= 0; } TXmlItem* TXmlItem::ForEach(XmlItemCallback cb, long jolly) { if (cb(*this, jolly)) return this; for (int n = 0; ; n++) { TXmlItem* c = GetChild(n); if (c == NULL) break; c = c->ForEach(cb, jolly); if (c) return c; } return NULL; } static bool GetEnclosedTextCallback(TXmlItem& item, long jolly) { TString* strText = (TString*)jolly; const TString& str = item.GetText(); if (!str.empty()) { if (!strText->empty()) *strText << " "; *strText << str; } return false; } bool TXmlItem::GetEnclosedText(TString& text) const { text.cut(0); ((TXmlItem*)this)->ForEach(GetEnclosedTextCallback, (long)&text); return text.not_empty(); } TXmlItem& TXmlItem::AddEnclosedText(const char* str) { TXmlItem* item = FindFirst(""); if (item == NULL) item = &AddChild(""); if (item->m_strText == NULL) item->SetText(str); else *item->m_strText << str; return *item; } TXmlItem& operator<<(TXmlItem& item, const char* str) { item.AddEnclosedText(str); return item; } void TXmlItem::Write(ostream& outf, int tab) const { if (!GetTag().empty()) { Spaces(outf, tab); outf << '<'; GetTag().print_on(outf); if (m_Attributes != NULL) { TAssoc_array& ass = *m_Attributes; FOR_EACH_ASSOC_OBJECT(ass, h, k, a) { outf << ' '; outf.write(k, strlen(k)); outf << '='; const TXmlAttr* attr = (const TXmlAttr*)a; attr->Write(outf); } } if (GetChildren() > 0) { outf << '>'; for (int n = 0; ; n++) { TXmlItem* c = GetChild(n); if (c == NULL) break; c->Write(outf, tab+1); } if (GetChild(n-1)->GetText().empty()) Spaces(outf, tab); outf << '<' << '/'; GetTag().print_on(outf); outf << '>'; } else outf << ' ' << '/' << '>'; } else GetText().print_on(outf); } void TXmlItem::AsString(TString& str) const { for (size_t nSize = 8192; ; nSize *= 2) { char* buf = str.get_buffer(nSize); memset(buf, 0, nSize); ostrstream outf(buf, nSize); Write(outf, 0); if (buf[nSize-1] == '\0') break; } } void TXmlItem::Save(const char* strFilename) const { ofstream outf(strFilename); Write(outf, 0); } static bool FindFirstCallback(TXmlItem& item, long jolly) { const char* strTag = (const char*)jolly; return item.GetTag() == strTag; } void TXmlItem::Destroy() { m_strTag.cut(0); if (m_strText) m_strText->cut(0); if (m_Attributes) m_Attributes->destroy(); if (m_Children) m_Children->destroy(); } TXmlItem* TXmlItem::FindFirst(const char* strTag) const { return ((TXmlItem*)this)->ForEach(FindFirstCallback, (long)strTag); } TXmlItem::TXmlItem() : m_strTag(7), m_Attributes(NULL), m_Children(NULL), m_strText(NULL) { } TXmlItem::~TXmlItem() { if (m_strText) delete m_strText; if (m_Attributes) delete m_Attributes; if (m_Children) delete m_Children; }