CLAM-Development  1.4.0
LibXmlDomReadingContext.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #ifndef _LibXmlDomReadingContext_hxx_
23 #define _LibXmlDomReadingContext_hxx_
24 
25 #include "Assert.hxx"
26 #include "LibXmlEncodings.hxx"
27 #include <libxml++/libxml++.h>
28 #include <sstream>
29 #include <list>
30 #include <string>
31 
32 namespace CLAM
33 {
34 class LibXmlDomDocumentHandler;
35 
41 {
42  LibXmlDomReadingContext * _parentContext;
43  xmlpp::Element * _context;
44  xmlpp::Node::NodeList _children;
45  xmlpp::Node::NodeList::iterator _currentChild;
46  xmlpp::Element::AttributeList _attributes;
47  std::stringstream _plainContentToParse;
48  std::list<std::string> _errors;
49 
50 public:
51  LibXmlDomReadingContext(xmlpp::Element * element)
52  {
53  _parentContext=0;
54  setAt(element);
55  }
56 
57  // TODO: Test this
59 
60  LibXmlDomReadingContext(LibXmlDomReadingContext * oldContext, const char * name)
61  {
62  _parentContext=oldContext;
63  setAt(oldContext->fetchElement(name));
64  }
65  void setAt(xmlpp::Element * element)
66  {
67  _context = element;
68  _children = _context->get_children();
69  _attributes = _context->get_attributes();
70  _currentChild=_children.begin();
71  fetchContent();
72  }
81  bool findElement(const char * name)
82  {
83  if (contentLeft()) return false;
84  if (_currentChild==_children.end()) return false; // No nodes left
85  xmlpp::Element * child = dynamic_cast<xmlpp::Element*>(*_currentChild);
86  CLAM_ASSERT(child,
87  "Can't change the context to a non element node");
88  if (child->get_name()!=U(name)) return false; // Name mismatch
89  return true;
90  }
98  xmlpp::Element * fetchElement(const char * name)
99  {
100  bool hasContentLeft = contentLeft();
101  CLAM_ASSERT(!hasContentLeft, "Fetching element with content left");
102  CLAM_ASSERT(_currentChild!=_children.end(),
103  "Accessing beyond DOM nodes");
104  xmlpp::Element * child = dynamic_cast<xmlpp::Element *>(*_currentChild);
105  CLAM_ASSERT(child,
106  "Can't change the context to a non element node");
107  CLAM_ASSERT(L(child->get_name())==name,
108  "XML element name should be the one expected");
109  _currentChild++;
110  fetchContent();
111  return child;
112  }
113 
115  {
118  return _parentContext;
119  }
120 
122  {
123  if (!contentLeft()) return;
124  std::ostringstream os;
125  os << "Unexpected content: '";
126  for (int c=_plainContentToParse.get(); not _plainContentToParse.eof(); c=_plainContentToParse.get())
127  os.put(c);
128  os << "' at position ";
129  os << getPath();
130  _errors.push_back(os.str());
131  }
133  {
134  if (_currentChild==_children.end()) return;
135  xmlpp::Element * child = dynamic_cast<xmlpp::Element*>(*_currentChild);
136  /*
137  if (!child)
138  _errors.push_back("Unexpected node type");
139  */
140 
141  std::ostringstream os;
142  os << "Unexpected Element: '";
143  os << L(child->get_name());
144  os << "' at position ";
145  os << getPath();
146 
147  _errors.push_back(os.str());
148  }
149 
150  bool extractAttribute(const char * attributeName, std::ostream & os)
151  {
152  xmlpp::Attribute * attribute =
153  _context->get_attribute(U(attributeName));
154  if (!attribute) return false;
155  os << L(attribute->get_value()) << std::flush;
156  return true;
157  }
158 
159  std::istream & reachableContent()
160  {
161  return _plainContentToParse;
162  }
169  {
170 // _plainContentToParse.clear(); // Clear any error flag
171  for (; _currentChild!=_children.end(); _currentChild++)
172  {
173  xmlpp::Node * child= *_currentChild;
174  if (dynamic_cast<xmlpp::CommentNode*>(child)) continue;
175  xmlpp::TextNode * textNode = dynamic_cast<xmlpp::TextNode*>(child);
176  if (!textNode) break;
177  _plainContentToParse << L(textNode->get_content());
178  }
179  _plainContentToParse << std::flush;
180  contentLeft();
181  }
182 
187  bool contentLeft()
188  {
189  int c = _plainContentToParse.peek();
190  while (not _plainContentToParse.eof())
191  {
192  if (!isspace(c)) return true;
193  _plainContentToParse.ignore();
194  c = _plainContentToParse.peek();
195  }
196  _plainContentToParse.clear();
197  return false;
198  }
199  std::list<std::string> errors()
200  {
201  return _errors;
202  }
203 
204  std::string getPath()
205  {
206  return L(_context->get_path());
207  // TODO: Remove the by hand way
208  std::string path;
209  if (_parentContext) path=_parentContext->getPath();
210  path += '/';
211  path += L(_context->get_name());
212  return path;
213  }
214 };
215 
216 } // Namespace CLAM
217 
218 #endif//_LibXmlDomReadingContext_hxx_
219 
220 
221