00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <fs/ut/fsXmlDoc.h>
00015 #include <fs/ut/fsStrUt.h>
00016
00017
00018 #if defined(FS_HAS_FSASSERT)
00019 # include <fs/sys/fsAssert.h>
00020 #else
00021 # include <cassert>
00022 # if !defined(FS_ASSERT)
00023 # define FS_ASSERT(exp) assert(exp)
00024 # endif
00025 # if !defined(FS_ASSERT_MSG)
00026 # define FS_ASSERT_MSG(exp, msg) assert(exp && msg)
00027 # endif
00028 # if !defined(FS_VERIFY)
00029 # define FS_VERIFY(exp) \
00030 { bool bExp = !!(exp); assert(bExp && #exp); bExp; }
00031 # endif
00032 # if !defined(FS_VERIFY_MSG)
00033 # define FS_VERIFY_MSG(exp, msg) \
00034 { bool bExp = !!(exp); assert(bExp && #exp && msg); bExp; }
00035 # endif
00036 # if !defined(FS_STATIC_ASSERT)
00037 # define FS_STATIC_ASSERT(exp) { char error[(exp) ? 1 : 0]; error; }
00038 # endif
00039 #endif
00040 #if !defined(FS_VERIFY_RETURN)
00041 # define FS_VERIFY_RETURN(exp) \
00042 if(!(exp)) { FS_ASSERT_MSG(0, #exp "<return>"); return; }
00043 #endif
00044 #if !defined(FS_VERIFY_RETURN_VAL)
00045 # define FS_VERIFY_RETURN_VAL(exp, ret) \
00046 if(!(exp)) { FS_ASSERT_MSG(0, #exp "<returns:>" #ret); return (ret); }
00047 #endif
00048
00049
00050 #include <string>
00051 #include <memory>
00052
00053
00054 #if defined(FS_HAS_FSMEMMGR)
00055 # include <fs/sys/fsMemMgr.h>
00056 #endif
00057
00058 #include <tinyxml/tinyxml.h>
00059
00060 using namespace fs::ut;
00061
00062
00063
00064 namespace {
00065
00066
00067
00068 class XmlDocImpl_t
00069 {
00070 public:
00071
00072 explicit XmlDocImpl_t(const char *pszFile);
00073 XmlDocImpl_t(const char *pszData, bool bUnused);
00074 bool IsValid() const;
00075
00076 bool Query(const char *pszQuery, int &nValue) const;
00077 bool Query(const char *pszQuery, const char *&pszText) const;
00078
00079 private:
00080
00081 XmlDocImpl_t();
00082 XmlDocImpl_t(const XmlDocImpl_t &);
00083 XmlDocImpl_t & operator = (const XmlDocImpl_t &);
00084
00086 int CountChdrn(const TiXmlElement *pElem, const char *pszLabel) const;
00088 const TiXmlElement * TravToLeaf(const char *pszQuery, std::string
00089 &strLeafReq) const;
00090
00091
00092
00093 typedef std::auto_ptr<TiXmlDocument> DocPtr_t;
00094 DocPtr_t m_ptrDoc;
00095 };
00096
00097 XmlDocImpl_t::XmlDocImpl_t(const char *pszFile)
00098 {
00099 FS_VERIFY_RETURN(pszFile);
00100
00101 DocPtr_t ptrDoc = DocPtr_t(new TiXmlDocument);
00102 FS_VERIFY_RETURN(ptrDoc->LoadFile(pszFile));
00103 FS_VERIFY_RETURN(!ptrDoc->Error());
00104
00105
00106
00107 m_ptrDoc = ptrDoc;
00108 }
00109
00110 XmlDocImpl_t::XmlDocImpl_t(const char *pszData, bool )
00111 {
00112 FS_VERIFY_RETURN(pszData);
00113
00114 DocPtr_t ptrDoc = DocPtr_t(new TiXmlDocument);
00115 ptrDoc->Parse(pszData);
00116 FS_VERIFY_RETURN(!ptrDoc->Error());
00117
00118
00119
00120 m_ptrDoc = ptrDoc;
00121 }
00122
00123 bool XmlDocImpl_t::IsValid() const
00124 {
00125 return m_ptrDoc.get() ? true : false;
00126 }
00127
00128 bool XmlDocImpl_t::Query(const char *pszQuery, int &nValue) const
00129 {
00130 FS_VERIFY_RETURN_VAL(pszQuery, false);
00131
00132 std::string strLeafReq;
00133 const TiXmlElement *pLeaf = TravToLeaf(pszQuery, strLeafReq);
00134
00135 if(!pLeaf)
00136 return false;
00137
00138 if(strLeafReq.empty())
00139 {
00140 const char *pszValue = pLeaf->GetText();
00141 if(pszValue)
00142 {
00143 nValue = ::atoi(pszValue);
00144 return true;
00145 }
00146 }
00147 else if(strLeafReq[0] == '#')
00148 {
00149 FS_VERIFY_RETURN_VAL(strLeafReq.size() > 1, false);
00150 nValue = CountChdrn(pLeaf, strLeafReq.c_str() + 1);
00151 return true;
00152 }
00153 else if(strLeafReq[0] == '@')
00154 {
00155 FS_VERIFY_RETURN_VAL(strLeafReq.size() > 1, false);
00156 int nTmp;
00157 if(pLeaf->Attribute(strLeafReq.c_str() + 1, &nTmp))
00158 {
00159 nValue = nTmp;
00160 return true;
00161 }
00162 }
00163
00164 return false;
00165 }
00166
00167 bool XmlDocImpl_t::Query(const char *pszQuery, const char *&pszText) const
00168 {
00169 FS_VERIFY_RETURN_VAL(pszQuery, false);
00170
00171 std::string strLeafReq;
00172 const TiXmlElement *pLeaf = TravToLeaf(pszQuery, strLeafReq);
00173
00174 if(!pLeaf)
00175 return false;
00176
00177 if(strLeafReq.empty())
00178 {
00179 const char *pszTmp = pLeaf->GetText();
00180 if(pszTmp)
00181 {
00182 pszText = pszTmp;
00183 return true;
00184 }
00185 }
00186 else if(strLeafReq[0] == '#')
00187 {
00188 FS_ASSERT_MSG(0, "Not implemented / required!");
00189 return false;
00190 }
00191 else if(strLeafReq[0] == '@')
00192 {
00193 FS_VERIFY_RETURN_VAL(strLeafReq.size() > 1, false);
00194 const char *pszTmp = pLeaf->Attribute(strLeafReq.c_str() + 1);
00195 if(pszTmp)
00196 {
00197 pszText = pszTmp;
00198 return true;
00199 }
00200 }
00201
00202 return false;
00203 }
00204
00205 int XmlDocImpl_t::CountChdrn(const TiXmlElement *pElem, const char *pszLabel)
00206 const
00207 {
00208 FS_ASSERT(pElem && pszLabel);
00209
00210 pElem = pElem->FirstChildElement(pszLabel);
00211
00212 int n = 0;
00213 while(pElem)
00214 {
00215 pElem = pElem->NextSiblingElement(pszLabel);
00216 ++n;
00217 }
00218
00219 return n;
00220 }
00221
00222 const TiXmlElement * XmlDocImpl_t::TravToLeaf(const char *pszQuery,
00223 std::string &strLeafReq) const
00224 {
00225 FS_ASSERT(pszQuery);
00226
00227 const TiXmlElement *pElem = 0;
00228 std::string strTokTmp;
00229
00230 fs::ut::str::Toknzr_t Toknzr(pszQuery, "/");
00231 for(const char *pszTok = Toknzr.Next(); pszTok; pszTok = Toknzr.Next())
00232 {
00233
00234 const char *pszBch = ::strchr(pszTok, '^');
00235
00236
00237 if(*pszTok == '@' || *pszTok == '#')
00238 {
00239 FS_VERIFY_RETURN_VAL(!pszBch, 0);
00240 FS_VERIFY_RETURN_VAL(pElem, 0);
00241
00242 strLeafReq = pszTok;
00243 return pElem;
00244 }
00245
00246
00247 int nBchIdx = 0;
00248 if(pszBch)
00249 {
00250 FS_VERIFY_RETURN_VAL(pElem, 0);
00251
00252
00253 nBchIdx = ::atoi(pszBch + 1);
00254
00255 strTokTmp = std::string(pszTok, pszBch - pszTok);
00256 pszTok = strTokTmp.c_str();
00257 }
00258
00259
00260 pElem = !pElem ? m_ptrDoc->FirstChildElement(pszTok)
00261 : pElem->FirstChildElement(pszTok);
00262
00263 if(!pElem)
00264 return 0;
00265
00266
00267 while(nBchIdx > 0)
00268 {
00269 pElem = pElem->NextSiblingElement(pszTok);
00270
00271 if(!pElem)
00272 return 0;
00273 else --nBchIdx;
00274 }
00275 }
00276
00277 return pElem;
00278 }
00279
00280 }
00281
00282
00283
00284 XmlDoc_t::XmlDoc_t(const char *pszFile):
00285 m_pImpl(new XmlDocImpl_t(pszFile))
00286 {
00287 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00288 }
00289
00290 XmlDoc_t::XmlDoc_t(const char *pszData, bool bUnused):
00291 m_pImpl(new XmlDocImpl_t(pszData, bUnused))
00292 {
00293 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00294 }
00295
00296 XmlDoc_t::~XmlDoc_t()
00297 {
00298 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00299 delete static_cast<XmlDocImpl_t *>(m_pImpl);
00300 }
00301
00302 bool XmlDoc_t::IsValid() const
00303 {
00304 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00305 return static_cast<XmlDocImpl_t *>(m_pImpl)->IsValid();
00306 }
00307
00313 bool XmlDoc_t::Query(const char *pszQuery, int &nValue) const
00314 {
00315 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00316 return static_cast<XmlDocImpl_t *>(m_pImpl)->Query(pszQuery, nValue);
00317 }
00318
00324 bool XmlDoc_t::Query(const char *pszQuery, const char *&pszText) const
00325 {
00326 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00327 return static_cast<XmlDocImpl_t *>(m_pImpl)->Query(pszQuery, pszText);
00328 }
00329