CLAM-Development  1.1
LibXmlDomReadingContext.hxx
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
00003  *                         UNIVERSITAT POMPEU FABRA
00004  *
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #ifndef _LibXmlDomReadingContext_hxx_
00023 #define _LibXmlDomReadingContext_hxx_
00024 
00025 #include "Assert.hxx"
00026 #include "LibXmlEncodings.hxx"
00027 #include <libxml++/libxml++.h>
00028 #include <sstream>
00029 #include <list>
00030 #include <string>
00031 #include <cstdio>
00032 
00033 namespace CLAM 
00034 {
00035 class LibXmlDomDocumentHandler;
00036 
00041 class LibXmlDomReadingContext
00042 {
00043         LibXmlDomReadingContext * _parentContext;
00044         xmlpp::Element * _context;
00045         xmlpp::Node::NodeList _children;
00046         xmlpp::Node::NodeList::iterator _currentChild;
00047         xmlpp::Element::AttributeList _attributes;
00048         std::stringstream _plainContentToParse;
00049         std::list<std::string> _errors;
00050 
00051 public:
00052         LibXmlDomReadingContext(xmlpp::Element * element)
00053         {
00054                 _parentContext=0;
00055                 setAt(element);
00056         }
00057 
00058         // TODO: Test this
00059         LibXmlDomReadingContext(LibXmlDomDocumentHandler & docHandler);
00060 
00061         LibXmlDomReadingContext(LibXmlDomReadingContext * oldContext, const char * name)
00062         {
00063                 _parentContext=oldContext;
00064                 setAt(oldContext->fetchElement(name));
00065         }
00066         void setAt(xmlpp::Element * element)
00067         {
00068                 _context = element;
00069                 _children = _context->get_children();
00070                 _attributes = _context->get_attributes();
00071                 _currentChild=_children.begin();
00072                 fetchContent();
00073         }
00082         bool findElement(const char * name)
00083         {
00084                 if (contentLeft()) return false;
00085                 if (_currentChild==_children.end()) return false; // No nodes left
00086                 xmlpp::Element * child = dynamic_cast<xmlpp::Element*>(*_currentChild);
00087                 CLAM_ASSERT(child,
00088                         "Can't change the context to a non element node");
00089                 if (child->get_name()!=U(name)) return false; // Name mismatch
00090                 return true;
00091         }
00099         xmlpp::Element * fetchElement(const char * name)
00100         {
00101                 bool hasContentLeft = contentLeft();
00102                 CLAM_ASSERT(!hasContentLeft, "Fetching element with content left");
00103                 CLAM_ASSERT(_currentChild!=_children.end(),
00104                         "Accessing beyond DOM nodes");
00105                 xmlpp::Element * child = dynamic_cast<xmlpp::Element *>(*_currentChild);
00106                 CLAM_ASSERT(child,
00107                         "Can't change the context to a non element node");
00108                 CLAM_ASSERT(L(child->get_name())==name,
00109                         "XML element name should be the one expected");
00110                 _currentChild++;
00111                 fetchContent();
00112                 return child;
00113         }
00114 
00115         LibXmlDomReadingContext * release()
00116         {
00117                 checkNoContentLeftOrError();
00118                 checkNoElementLeftOrError();
00119                 return _parentContext;
00120         }
00121 
00122         void checkNoContentLeftOrError()
00123         {
00124                 if (!contentLeft()) return;
00125                 std::ostringstream os;
00126                 os << "Unexpected content: '";
00127                 for (int c=_plainContentToParse.get(); c!=EOF; c=_plainContentToParse.get())
00128                         os.put(c);
00129                 os << "' at position ";
00130                 os << getPath();
00131                 _errors.push_back(os.str());
00132         }
00133         void checkNoElementLeftOrError()
00134         {
00135                 if (_currentChild==_children.end()) return;
00136                 xmlpp::Element * child = dynamic_cast<xmlpp::Element*>(*_currentChild);
00137                 /*
00138                 if (!child)
00139                         _errors.push_back("Unexpected node type");
00140                 */
00141 
00142                 std::ostringstream os;
00143                 os << "Unexpected Element: '";
00144                 os << L(child->get_name());
00145                 os << "' at position ";
00146                 os << getPath();
00147 
00148                 _errors.push_back(os.str());
00149         }
00150 
00151         bool extractAttribute(const char * attributeName, std::ostream & os)
00152         {
00153                 xmlpp::Attribute * attribute =
00154                         _context->get_attribute(U(attributeName));
00155                 if (!attribute) return false;
00156                 os << L(attribute->get_value()) << std::flush;
00157                 return true;
00158         }
00159 
00160         std::istream & reachableContent()
00161         {
00162                 return _plainContentToParse;
00163         }
00169         void fetchContent()
00170         {
00171 //              _plainContentToParse.clear(); // Clear any error flag
00172                 for (; _currentChild!=_children.end(); _currentChild++)
00173                 {
00174                         xmlpp::Node * child= *_currentChild;
00175                         if (dynamic_cast<xmlpp::CommentNode*>(child)) continue;
00176                         xmlpp::TextNode * textNode = dynamic_cast<xmlpp::TextNode*>(child);
00177                         if (!textNode) break;
00178                         _plainContentToParse << L(textNode->get_content());
00179                 }
00180                 _plainContentToParse << std::flush;
00181                 contentLeft();
00182         }
00183 
00188         bool contentLeft()
00189         {
00190                 int c = _plainContentToParse.peek();
00191                 while (c != EOF)
00192                 {
00193                         if (!isspace(c)) return true;
00194                         _plainContentToParse.ignore();
00195                         c = _plainContentToParse.peek();
00196                 }
00197                 _plainContentToParse.clear();
00198                 return false;
00199         }
00200         std::list<std::string> errors()
00201         {
00202                 return _errors;
00203         }
00204 
00205         std::string getPath()
00206         {
00207                 std::string path;
00208                 if (_parentContext) path=_parentContext->getPath();
00209                 path += '/';
00210                 path += L(_context->get_name());
00211                 return path;
00212         }
00213 };
00214 
00215 } // Namespace CLAM
00216 
00217 #endif//_LibXmlDomReadingContext_hxx_
00218 
00219 
00220