CLAM-Development
1.1
|
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