#line 1 "/user/cvsspst/ees1cg/RAVL/RAVL-0.7/Core/System/XMLStream.hh" // This file is part of RAVL, Recognition And Vision Library // Copyright (C) 2001, University of Surrey // This code may be redistributed under the terms of the GNU Lesser // General Public License (LGPL). See the lgpl.licence file for details or // see http://www.gnu.org/copyleft/lesser.html // file-header-ends-here #ifndef RAVLXMLSTREAM_HEADER #define RAVLXMLSTREAM_HEADER 1 ///////////////////////////////////////////////////////// //! rcsid="$Id: XMLStream.hh,v 1.10 2002/08/12 13:58:00 craftit Exp $" //! lib=RavlCore //! docentry="Ravl.Core.XML" //! author="Charles Galambos" //! file="Ravl/Core/System/XMLStream.hh" #include "Ravl/Stream.hh" #include "Ravl/StrStream.hh" #include "Ravl/String.hh" #include "Ravl/Stack.hh" #include "Ravl/RCHash.hh" #include "Ravl/HashIter.hh" #include "Ravl/RefCounter.hh" #include "Ravl/TypeName.hh" #include "Ravl/SArray1d.hh" #include "Ravl/SArr1Iter.hh" namespace RavlN { enum XMLTagOpsT { XMLEndTag, XMLContent, XMLIndent,XMLIndentDown, XMLEmptyTag, XMLBeginTag, XMLComment }; //! userlevel=Normal //: Exception issued when an parse error occurs. class ExceptionInvalidStreamC : public ExceptionC { public: ExceptionInvalidStreamC(const char *ntext) : ExceptionC(ntext) {} //: Constructor ExceptionInvalidStreamC(const char *ntext,bool copy) : ExceptionC(ntext,copy) {} //: Constructor. // if copy is true, make a copy of ntext. }; //! userlevel=Advanced //: Class for handling XML attributes. // SMALL object.

// Note: This only keeps a reference to the data, not an // actual copy. template class XMLAttributeC { public: XMLAttributeC(const StringC &nm,DataT &ndat) : name(nm), dat(ndat) {} //: Constructor. StringC &Name() { return name; } //: Access name of attribute. const StringC &Name() const { return name; } //: Access name of attribute. DataT &Data() { return dat; } //: Access data in attribute. const DataT &Data() const { return dat; } //: Access data in attribute. protected: StringC name; DataT &dat; }; //! userlevel=Develop //: Information about the current element being processed. class XMLElementBodyC : public RCBodyC { public: XMLElementBodyC() {} //: Constructor. XMLElementBodyC(const StringC &nm,bool anEmptyTag = false) : name(nm), emptyTag(anEmptyTag) {} //: Constructor. XMLElementBodyC(const StringC &nm,const RCHashC &attrs,bool anEmptyTag = false) : name(nm), attribs(attrs), emptyTag(anEmptyTag) {} //: Constructor. StringC &Name() { return name; } //: Name of context. const StringC &Name() const { return name; } //: Name of context. RCHashC &Attributes() { return attribs; } //: Get the current attributes. const RCHashC &Attributes() const { return attribs; } //: Get the current attributes. void SetEmptyTag(bool v) { emptyTag = v; } //: Set empty tag flag. bool IsEmptyTag() const { return emptyTag; } //: Is tag empty ? protected: StringC name; RCHashC attribs; bool emptyTag; }; //! userlevel=Advanced //: Information about the current element being processed. class XMLElementC : public RCHandleC { public: XMLElementC() {} //: Constructor. XMLElementC(const StringC &nm,bool anEmptyTag = false) : RCHandleC(*new XMLElementBodyC(nm,anEmptyTag)) {} //: Constructor. XMLElementC(const StringC &nm,const RCHashC &attrs,bool anEmptyTag = false) : RCHandleC(*new XMLElementBodyC(nm,attrs,anEmptyTag)) {} //: Constructor. StringC &Name() { return Body().Name(); } //: Name of context. const StringC &Name() const { return Body().Name(); } //: Name of context. RCHashC &Attributes() { return Body().Attributes(); } //: Get the current attributes. const RCHashC &Attributes() const { return Body().Attributes(); } //: Get the current attributes. bool IsEmptyTag() const { return Body().IsEmptyTag(); } //: Is tag empty ? void SetEmptyTag(bool v) { Body().SetEmptyTag(v); } //: Set empty tag flag. }; //! userlevel=Develop //: Common XML operations. // Stuff common to handling XML input and output. class XMLBaseBodyC : public RCBodyVC { public: XMLBaseBodyC(); //: Constructor. XMLElementC &Context() { return context.Top(); } //: Access current context. bool IsContext() const { return !context.IsEmpty(); } //: Are we in a valid context ? const XMLElementC &Context() const { return context.Top(); } //: Access current context. bool EndOfContext(const StringC &nm) { // Check name here ? if(context.IsEmpty()) return false; context.DelTop(); return true; }; //: End the current context. bool EndOfContext() { if(context.IsEmpty()) return false; context.DelTop(); return true; }; //: End the current context. bool StartContext(const StringC &str,bool emptyTag = false) { context.Push(XMLElementC(str,emptyTag)); SetContent(false); return true; }; //: Start a context. bool StartContext(const StringC &str,const RCHashC &attrs,bool emptyTag = false) { context.Push(XMLElementC(str,attrs,emptyTag)); SetContent(false); return true; }; //: Start a context. bool StartContext(const XMLElementC &elem) { context.Push(elem); SetContent(false); return true; }; //: Start a context. bool IsStrict() const { return strict; } //: In strict mode ? // if true issue errors if XML consitancy check fails in reading or writing. bool IsContent() const { return contents; } //: Got content ? // True if content has been found. void SetContent(bool cont) { contents = cont; } //: Set got content. UIntT LevelsNested() const { return context.Size(); } //: Number of open elements in the stack. bool GetAttib(const StringC &name,StringC &val) { RavlAssert(!context.IsEmpty()); StringC *sv = context.Top().Attributes().Lookup(name); if(sv == 0) return false; val = *sv; return true; } //: Set string attribute. void SetAttrib(const StringC &value,const StringC &val) { RavlAssert(!context.IsEmpty()); context.Top().Attributes()[value] = val; } //: Set a string valued attribute. protected: bool strict; // Be strict about usage. StackC context; bool contents; }; //! userlevel=Advanced //: Common XML operations. // Stuff common to handling XML input and output. class XMLBaseC : public RCHandleC { public: XMLBaseC() {} //: Default constructor. // Creates an invalid handle. XMLBaseC(bool) : RCHandleC(*new XMLBaseBodyC()) {} //: Constructor. static StringC EncodeLitteral(const StringC &str); //: Convert a string into a form that will not confuse XML. static StringC DecodeLitteral(const StringC &str); //: Decode a string from its XML encoding to the original string. XMLElementC &Context() { return Body().Context(); } //: Access current context. bool IsContext() const { return Body().IsContext(); } //: Are we in a valid context ? StringC ContextName() const { if(!IsContext()) return StringC(); return Context().Name(); } //: Get the name of the current context (the last open tag.) const XMLElementC &Context() const { return Body().Context(); } //: Access current context. bool StartContext(const StringC &str,bool emptyTag = false) { return Body().StartContext(str,emptyTag); } //: Start a new element. bool StartContext(const StringC &str,const RCHashC &attrs,bool emptyTag = false) { return Body().StartContext(str,attrs,emptyTag); } //: Start a new element bool StartContext(const XMLElementC &elem) { return Body().StartContext(elem); } //: Start a new element bool EndOfContext(const StringC &nm) { return Body().EndOfContext(nm); } //: End the current context. bool EndOfContext() { return Body().EndOfContext(); } //: End the current context. bool IsStrict() const { return Body().IsStrict(); } //: In strict mode ? // if true issue errors if XML consitancy check fails in reading or writing. bool IsContent() const { return Body().IsContent(); } //: Got content ? // True if content has been found. void SetContent(bool cont) { Body().SetContent(cont); } //: Set got content. UIntT LevelsNested() const { return Body().LevelsNested(); } //: Number of open elements in the stack. bool GetAttrib(const StringC &name,StringC &val) { return Body().GetAttib(name,val); } //: Set string attribute. void SetAttrib(const StringC &name,const StringC &val) { Body().SetAttrib(name,val); } //: Set a string valued attribute. protected: }; //! userlevel=Normal //: XML Input Stream. // Provides extra functionality for parsing of XML streams. class XMLIStreamC : public IStreamC, public XMLBaseC { public: XMLIStreamC(IStreamC &is); //: Construct from an ordinary stream. XMLIStreamC(const StringC &fn) : IStreamC(fn), XMLBaseC(true) {} //: Construct from an ordinary stream. XMLTagOpsT ReadTag(StringC &name,RCHashC &attr); //: Read a tag from a stream. // returns XMLBeginTag, XMLEndTag or XMLEmptyTag. // This will skip comments and DTD info, and anything else it doesn't understand. XMLTagOpsT ReadTag(StringC &name) { RCHashC attr; return ReadTag(name,attr); } //: Read a tag from a stream. // returns XMLBeginTag, XMLEndTag or XMLEmptyTag. // This will skip comments and DTD info, and anything else it doesn't understand. bool SkipElement(); //: Skip to after the end of the current element. XMLTagOpsT SkipToElement(const StringC &elementName,RCHashC &attr); //: Skip to named element. // This will skip to the next tag of the given name. // if the Current context ends it will return XMLEndTag. StringC ReadID(); //: Read an ID from the stream. // This will skip any intial white space, but will // return an empty string if an invalid characters is found. bool GetAttrib(const StringC &name,StringC &val) { return XMLBaseC::GetAttrib(name,val); } //: Get a string attribute for entity. // This can only be called between StartTag and StartContents. // This returns true if attribute is set. bool GetAttrib(const StringC &name,IntT &val); //: Get an integer attribute for entity. // This can only be called between StartTag and StartContents. // This returns true if attribute is set. bool GetAttrib(const StringC &name,UIntT &val); //: Get an unsigned integer attribute for entity. // This can only be called between StartTag and StartContents. // This returns true if attribute is set. bool GetAttrib(const StringC &name,RealT &val); //: Get a real valued attribute for entity. // This can only be called between StartTag and StartContents. // This returns true if attribute is set. template bool GetAttrib(const StringC &name,const DataT &val) { StringC strval; if(!XMLBaseC::GetAttrib(name,strval)) return false; StrIStreamC istr(strval); istr >> val; return true; } //: Get an abitary valued attribute for entity. // This can only be called between StartTag and StartContents. // The attribute value is stored using its default streaming // operators. (ostream and istream) protected: StringC ReadAttrib(); //: Read attribute and add it to the current context. // returns the name of the attrbute read. }; //! userlevel=Normal //: XML Output Stream. // Provides extra functionality for generation of XML streams. class XMLOStreamC : public OStreamC, public XMLBaseC { public: XMLOStreamC(OStreamC &os); //: Construct from an ordinary stream. XMLOStreamC(const StringC &fn) : OStreamC(fn), XMLBaseC(true) {} //: Construct from an ordinary stream. void StartTag(const StringC &name, const RCHashC &attribs, bool emptyTag = false); //: Begin writting a tag with the given attributes. void StartTag(const StringC &name, bool emptyTag = false); //: Begin writting a tag with the given attributes. void StartContents(); //: Call before writting contents of entity to stream. void EndTag(const StringC &name); //: End writting a tag. // if strict checking is enabled, name will be check against that of the open tag. void EndTag(); //: End writting current entity. void Indent(int off = 0); //: Indent the following line appropriatly. template void SetAttrib(const StringC &name,const DataT &val) { StrOStreamC ostr; ostr << val; XMLBaseC::SetAttrib(name,ostr.String()); } //: Set an abitary valued attribute for entity. // This can only be called between StartTag and StartContents. // The attribute value is stored using its default streaming // operators. (ostream and istream) void SetAttrib(const StringC &name,const StringC &val) { XMLBaseC::SetAttrib(name,val); } //: Set an integer attribute for entity. // This can only be called between StartTag and StartContents. void SetAttrib(const StringC &name,const IntT &val); //: Set an integer attribute for entity. // This can only be called between StartTag and StartContents. void SetAttrib(const StringC &name,const UIntT &val); //: Set an unsigned integer attribute for entity. // This can only be called between StartTag and StartContents. void SetAttrib(const StringC &name,const char * &val); //: Set a 'C' string attribute for entity. // This can only be called between StartTag and StartContents. void SetAttrib(const StringC &name,const RealT &val); //: Set a real valued attribute for entity. // This can only be called between StartTag and StartContents. }; inline XMLOStreamC &operator<<(XMLOStreamC &strm,const XMLElementC &elem) { strm.StartContext(elem); return strm; } //: Output a element, well start to. inline ostream &operator<<(ostream &strm,const XMLTagOpsT &elem) { RavlAssertMsg(0,"XMLTagOpsT saved to non-xml stream. \n"); return strm; } //: Catch silly mistakes. XMLOStreamC &operator<<(XMLOStreamC &strm,const XMLTagOpsT &elem); //: Do an output stream op. XMLIStreamC &operator>>(XMLIStreamC &strm,const XMLTagOpsT &elem); //: Do an input stream op. template inline XMLOStreamC &operator<<(XMLOStreamC &strm,const XMLAttributeC &elem) { strm.SetAttrib(elem.Name(),elem.Data()); return strm; } //: Write out an attribute. template inline XMLIStreamC &operator>>(XMLIStreamC &strm,const XMLAttributeC &elem) { strm.GetAttrib(elem.Name(),const_cast &>(elem).Data()); return strm; } //: Write out an attribute. template XMLAttributeC XMLAttribute(const StringC &nm,const DataT &dat) { return XMLAttributeC(nm,const_cast(dat)); } //: Setup an XML attribute. inline XMLElementC XMLStartTag(const StringC &name) { return XMLElementC(name); } //: Start writing a XML start tag. template XMLOStreamC &operator<<(XMLOStreamC &strm,const SArray1dC &arr) { strm << XMLStartTag("array") << XMLAttribute("size",arr.Size()) << XMLContent; for(SArray1dIterC it(arr);it;it++) { strm << XMLIndent << XMLStartTag("data") << XMLContent << *it; strm << XMLEndTag; } strm << XMLIndentDown << XMLEndTag; return strm; } template XMLIStreamC &operator>>(XMLIStreamC &strm,SArray1dC &arr) { UIntT size = 0; StringC name; if(strm.ReadTag(name) != XMLBeginTag) throw ExceptionInvalidStreamC("Unexpected tag when reading SArray1dC "); strm >> XMLAttribute("size",size); SArray1dC ret(size); for(SArray1dIterC it(ret);it;it++) { XMLTagOpsT tt = strm.ReadTag(name); if(tt == XMLEndTag) { //cerr << "Found end:" << name << "\n"; break; // Found end of array tag. } if(tt == XMLEmptyTag ) throw ExceptionInvalidStreamC("Unexpected tag when reading SArray1dC "); if(name != "data") { cerr << "WARNING: Read array ignoring tag '" << name << "'\n"; strm.SkipElement(); continue; } strm >> *it; //cerr << "Got data " << *it << "\n"; strm >> XMLEndTag; } //cerr << "Read of " << size << " items complete.\n"; arr = ret; return strm; } template XMLOStreamC &operator<<(XMLOStreamC &strm,const HashC &elem) { strm << XMLIndent << XMLStartTag("hashmap") << XMLAttribute("class",TypeName(typeid(HashC))) << XMLContent; for(HashIterC it(elem);it;it++) { strm << XMLIndent << XMLStartTag("map") << XMLContent; strm << XMLIndent << XMLStartTag("key") << XMLContent << it.Key(); strm << XMLEndTag; strm << XMLIndent << XMLStartTag("data") << XMLContent << it.Data(); strm << XMLEndTag; strm << XMLIndentDown << XMLEndTag; } strm << XMLIndentDown << XMLEndTag; return strm; } //: Write out a hash table. // This also serves as an example. template XMLIStreamC &operator>>(XMLIStreamC &strm,HashC &elem) { // Assume we've got the open tag. for(;;) { } return strm; } //: Read in a hash table. // This also serves as an example. } #endif