#include #include #include #include namespace xml { enum EItems { unknown, xmldecl, comment, processing_instruction, doctypedecl, element, chardata, cdsect }; class basic_read_iterator : public std::iterator { class exception { }; typedef basic_read_iterator MyType; typedef std::string StringType; typedef std::vector > AtributesType; class Impl { class AutoXmlChar { xmlChar* m_p; public: explicit AutoXmlChar(xmlChar* p) : m_p(p) { } operator StringType() const { return StringType(reinterpret_cast(m_p)); } ~AutoXmlChar() { xmlFree(m_p); } }; std::vector< std::pair > d_attributes; public: const AtributesType& attributes() { // if ( d_attributes.empty() ) { while ( xmlTextReaderMoveToNextAttribute(m_Reader) ) { d_attributes.push_back(std::pair(AutoXmlChar(xmlTextReaderName(m_Reader)), AutoXmlChar(xmlTextReaderValue(m_Reader)))); } } return d_attributes; } xmlTextReaderPtr m_Reader; StringType d_str; StringType d_endtag; boost::shared_ptr p_body; void (Impl::*p_state)(); ~Impl() { if ( d_endtag.empty() ) { xmlFreeTextReader(m_Reader); } } Impl(xmlTextReaderPtr Reader, const StringType& endtag) : m_Reader(Reader), p_state(&MyType::Impl::read_element), d_endtag(endtag) { } Impl(const char* FileName) : m_Reader(xmlNewTextReaderFilename(FileName)), p_state(&MyType::Impl::read_element) { if ( !m_Reader ) throw exception(); } void at_end(){} void read_element() { switch ( xmlTextReaderRead(m_Reader) ) { case 0: p_state = &MyType::Impl::at_end; return; case 1: break; default: throw exception(); } const int ret = xmlTextReaderNodeType(m_Reader); switch ( ret ) { case 1: d_str = AutoXmlChar(xmlTextReaderName(m_Reader)); readattributes(); if ( xmlTextReaderIsEmptyElement(m_Reader) ) { p_state = &MyType::Impl::element_read; } else { p_body.reset(new Impl(m_Reader, d_str)); p_state = &MyType::Impl::start_tag_read; } p_state = ( xmlTextReaderIsEmptyElement(m_Reader) )? &MyType::Impl::element_read : &MyType::Impl::start_tag_read; break; case 8: // skipp comments d_str = AutoXmlChar(xmlTextReaderValue(m_Reader)); p_state = &MyType::Impl::comment_read; break; case 4: case 3: d_str = AutoXmlChar(xmlTextReaderValue(m_Reader)); p_state = &MyType::Impl::character_data_read; break; case 15: p_state = &MyType::Impl::at_end; break; default: throw exception(); } } void comment_read() { read_element(); } void character_data_read() { read_element(); } void element_read() { read_element(); } void start_tag_read() { assert(p_body); if ( p_body->p_state == &MyType::Impl::read_element ) { switch ( xmlTextReaderNext(m_Reader) ) { case 0: p_state = &MyType::Impl::at_end; return; case 1: break; default: throw exception(); } switch ( xmlTextReaderNodeType(m_Reader) ) { case 1: d_str = AutoXmlChar(xmlTextReaderName(m_Reader)); readattributes(); if ( xmlTextReaderIsEmptyElement(m_Reader) ) { p_state = &MyType::Impl::element_read; } else { p_body.reset(new Impl(m_Reader, d_str)); p_state = &MyType::Impl::start_tag_read; } p_state = ( xmlTextReaderIsEmptyElement(m_Reader) )? &MyType::Impl::element_read : &MyType::Impl::start_tag_read; break; case 8: // skipp comments break; case 3: d_str = AutoXmlChar(xmlTextReaderValue(m_Reader)); p_state = &MyType::Impl::character_data_read; break; case 15: p_state = &MyType::Impl::at_end; break; default: throw exception(); } } else { while ( p_body->p_state != &MyType::Impl::at_end ) { (p_body.get()->*(p_body->p_state))(); } // p_body->impl.reset(); read_element(); } } void readattributes() { d_attributes.clear(); } }; boost::shared_ptr impl; basic_read_iterator(boost::shared_ptr& impl_) : impl(impl_) { operator++(); } public: basic_read_iterator(){} explicit basic_read_iterator(const char* File) : impl(new Impl(File)) { operator++(); } basic_read_iterator(const MyType& rhs) : impl(rhs.impl){} MyType& operator=(const MyType& rhs) { impl = rhs.impl; return *this; } ~basic_read_iterator(){} const MyType& operator*() const { return *this; } const MyType* operator->() const { return this; } MyType& operator++() { assert(impl); (impl.get()->*(impl->p_state))(); if (impl->p_state == &MyType::Impl::at_end) impl.reset(); return *this; } MyType operator++(int) { MyType copy(*this); operator++(); return copy; } bool operator==(const MyType& rhs) const { return impl == rhs.impl; } bool operator!=(const MyType& rhs) const { return impl != rhs.impl; } EItems type() const { assert(impl); if (impl->p_state == &MyType::Impl::element_read || impl->p_state == &MyType::Impl::start_tag_read) return element; else if (impl->p_state == &MyType::Impl::character_data_read) return chardata; else if (impl->p_state == &MyType::Impl::comment_read) return comment; else return unknown; } StringType str() const { assert(impl); return impl->d_str; } const std::vector< std::pair >& attributes() const { assert(impl); return impl->attributes(); } MyType begin() const { assert(impl); // assert(impl->p_body); if ( impl->p_body ) { return MyType(impl->p_body); } else { return MyType(); } } MyType end() const { return MyType(); } }; typedef basic_read_iterator read_iterator; }