fs/ut/fsXmlDoc.cpp

Go to the documentation of this file.
00001 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00002 /*                          _______      ______    ______          __      */
00003 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~    / ____(_)___ / ___ /)  / ____/___  ____/ /__    */
00004 /*     [fsXmlDoc]         / /_  / / __ \\__ \|/  / /   / __ \/ __  / _ \   */
00005 /*       rev. 4          / __/ / / /_/ /__/ /   / /___/ /_/ / /_/ /  __/   */
00006 /*    13th Jan 2007     /_/   /_/ ,___/____/    \____/\____/\__,_/\___/    */
00007 /*     [x] stable              /_/ (c) 2005-7 Filip STOKLAS (FipS)         */
00008 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~       http://HOLE.4FipS.com/fips_code.php          */
00009 /*                                                                         */
00010 /* This code is free for personal and commercial use. You may redistribute */
00011 /* it by any means. If you use the code for your own projects please give  */
00012 /* me credit. Please send a bug report. Don't alter or remove this header! */
00013 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00014 #include <fs/ut/fsXmlDoc.h>
00015 #include <fs/ut/fsStrUt.h> // tokenizer
00016 
00017 // >>> COMMON SUPPORT BLOCK (rev. 6)
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 // <<< COMMON SUPPORT BLOCK (rev. 6)
00049 
00050 #include <string>
00051 #include <memory> // auto_ptr
00052 
00053 // provide detailed memory tracking information
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 //--- ANONYMOUS NAMESPACE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00063 //---------------------------------------------------------------------------
00064 namespace {
00065 //---------------------------------------------------------------------------
00066 //--- CLASS XmlDocImpl_t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
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     //--- TRANSFER THE STATE ---
00106     
00107     m_ptrDoc = ptrDoc;
00108 }
00109 //---------------------------------------------------------------------------
00110 XmlDocImpl_t::XmlDocImpl_t(const char *pszData, bool /*bUnused*/)
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     //--- TRANSFER THE STATE ---
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) // non-existent XML path
00136         return false;
00137 
00138     if(strLeafReq.empty()) // return the content
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] == '#') // count children
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] == '@') // get the attribute
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) // non-existent XML path
00175         return false;
00176         
00177     if(strLeafReq.empty()) // return the content
00178     {
00179         const char *pszTmp = pLeaf->GetText();
00180         if(pszTmp)
00181         {
00182             pszText = pszTmp;
00183             return true;
00184         }
00185     }
00186     else if(strLeafReq[0] == '#') // count children
00187     {
00188         FS_ASSERT_MSG(0, "Not implemented / required!");
00189         return false;
00190     }
00191     else if(strLeafReq[0] == '@') // get the attribute
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         // look for the branching symbol '^'
00234         const char *pszBch = ::strchr(pszTok, '^');
00235         
00236         // '#' and '@' are always treated as a leaf
00237         if(*pszTok == '@' || *pszTok == '#')
00238         {
00239             FS_VERIFY_RETURN_VAL(!pszBch, 0); // unexpected '^'
00240             FS_VERIFY_RETURN_VAL(pElem, 0); // '@/#' invalid for the root
00241             
00242             strLeafReq = pszTok;
00243             return pElem;
00244         }
00245                         
00246         // get the branching index, crop the token
00247         int nBchIdx = 0;
00248         if(pszBch)
00249         {
00250             FS_VERIFY_RETURN_VAL(pElem, 0); // '^' invalid for the root
00251         
00252             // get the branching index
00253             nBchIdx = ::atoi(pszBch + 1);
00254             // crop the branching information
00255             strTokTmp = std::string(pszTok, pszBch - pszTok);
00256             pszTok = strTokTmp.c_str(); // substitute
00257         }
00258                                                                 
00259         // go down the tree (use the doc or the previous element)
00260         pElem = !pElem ? m_ptrDoc->FirstChildElement(pszTok)
00261          : pElem->FirstChildElement(pszTok);
00262         
00263         if(!pElem) // requested element doesn't exist
00264             return 0;
00265                                         
00266         // switch to the requested branch (on the same level)
00267         while(nBchIdx > 0)
00268         {
00269             pElem = pElem->NextSiblingElement(pszTok);
00270 
00271             if(!pElem) // out of range
00272                 return 0;
00273             else --nBchIdx;
00274         }
00275     }
00276     
00277     return pElem; // bare leaf (strLeafReq is empty)
00278 }
00279 //---------------------------------------------------------------------------
00280 } // anonymous namespace
00281 //---------------------------------------------------------------------------
00282 //--- CLASS XmlDoc_t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
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 //---------------------------------------------------------------------------

FipS' Code (Thu Feb 15 22:43:35 2007) - (c) Filip STOKLAS (FipS) - [ www ] [ Guest Book ]