/****************************************************************************
* gxmlwf.h :
* header file for parsing well-formed XML doc
*
* Change Log :
* May 14 1998 Initial version, Liujian Qian
*
* $Id: gxmlwf.h,v 1.7 1999/01/27 21:00:02 qian Exp $
***************************************************************************/
#ifndef _GXMLWF_H_
#define _GXMLWF_H_
#ifndef NOP
#define NOP
#endif
#include "gdatapipe.h"
#include "xmlparse.h"
#include <assert.h>
class GXMLElement;
/**
* structure for the XML attribute; a name-value pair
*/
class GXMLAttr
{
public:
char name[MAX_NAME];
char* value;
GXMLAttr* next;
GXMLElement* owner;
public:
NOP GXMLAttr();
NOP GXMLAttr(const char* name, const char* val);
NOP ~GXMLAttr();
bool operator==(const GXMLAttr& att) ;
bool operator==(const char* _name) ;
void set(const char* _name, const char* _value);
friend ostream& operator<<(ostream& o, const GXMLAttr& a);
};
/**
* structure for the XML element node.
* All the attributes are public so as to
* make the access simple and direct.
*/
class GXMLElement
{
public:
GXMLElement* parent;
GXMLElement* children; //all the elements that are below (within) this one
GXMLElement* next; //all the elements that are in the same level.
int n_children;
char name[MAX_NAME];
int n_attr;
GXMLAttr* attrs;
DataPipe content;
public:
NOP GXMLElement();
NOP ~GXMLElement();
GXMLElement& operator=(const GXMLElement& a);
/**
* add an element as its child. Appened to the end of *children.
* The children of an element are the ones that live within the
* scope of it. The list of children is headed by the field
* "children".
*/
void addChild(GXMLElement* el);
/**
* add an attribute (name,value) pair to the list of attributes.
* All attributes are chained using the GXMLAttr->next filed, the
* head being "attrs".
*/
void addAttr(GXMLAttr* att);
/**
* determin whether this is a leaf element.
* An elment is a leaf if it has no child elements.
*/
bool isLeaf() const;
/**
* link the next element
*/
void setNext(GXMLElement* el);
/**
* set element "el" as the parent of this element.
* Each element (except root) can have only one parent;
* The root element has no parent.
*/
void setParent(GXMLElement* el);
/**
* determine whether the content is all white space (empty content).
*/
bool isAllSpace() ;
/**
* get the value for the specified attribute
*/
const char* getAttributeValue(const char* attr);
bool operator==(const GXMLElement& el) ;
bool operator==(const char* _name) ;
friend ostream& operator<<(ostream& o, const GXMLElement& a);
} ;
/**
* @internal
*
* Internal class.
* GXMLElementStk is the stack used during parsing
*/
class GXMLElementStk
{
public:
enum { MAX_STK_SZ = 10 }; // 10 ought be enough
private:
const GXMLElement* _stk[MAX_STK_SZ];
short _top;
public:
NOP GXMLElementStk() :_top(0) {};
NOP ~GXMLElementStk() {};
inline GXMLElementStk& operator=(const GXMLElementStk& t);
inline void push(const GXMLElement* p);
inline const GXMLElement* pop();
inline const GXMLElement* top();
inline const GXMLElement* second();
inline const GXMLElement* bottom();
inline void updateTop(const GXMLElement* p);
inline short size() {return _top; }
inline bool isFull() { return _top >= MAX_STK_SZ; }
inline bool isEmpty(){ return _top == 0; }
inline void reset() { _top = 0; }
};
inline void GXMLElementStk::push(const GXMLElement* ptr)
{
if(isFull()) {
cerr<<"XML Element Stack overflow!\n";
abort();
}
_stk[_top++] = ptr;
}
inline const GXMLElement* GXMLElementStk::pop()
{
if(!isEmpty())
return _stk[--_top];
else return 0;
}
inline const GXMLElement* GXMLElementStk::top()
{
if(!isEmpty())
return _stk[_top-1];
else return 0;
}
inline const GXMLElement* GXMLElementStk::second()
{
if(_top > 1)
return _stk[_top-2];
else return 0;
}
inline const GXMLElement* GXMLElementStk::bottom()
{
if(! isEmpty())
return _stk[0];
else return 0;
}
inline void GXMLElementStk::updateTop(const GXMLElement* p)
{
assert(! isEmpty());
_stk[_top-1] = p;
}
inline GXMLElementStk& GXMLElementStk::operator=(const GXMLElementStk& t)
{
_top = t._top;
memcpy((char*)_stk, (char*)&t._stk, sizeof(GXMLElement*)*MAX_STK_SZ);
return *this;
}
static int READ_SIZE = 1024*8;
/**
* The GFC XML processor.
* This contains a wrapper of James Clark's expat parser
*/
class GXMLProcessor
{
char xml_file[256];
const char *encoding;
GXMLElementStk *stk;
XML_Parser parser;
GXMLElement *root; //the root element
public:
NOP GXMLProcessor(const char* xml);
NOP ~GXMLProcessor();
/**
* parse an XML file.
* The logical structure of the document is represented by a tree
* of elemnets.
* The root of the tree can be accessed using getRoot() method.
* Returns 1 if no error encountered; returns 0 if it is not a
* well-formed XML file.
*/
int parseStream();
/**
* return the root element of the currently built xml tree.
* All the other elements can be accessed through traversal
* starting at root.
*/
GXMLElement* getRoot() {return root; }
/**
* search for an element with given key in the document tree.
* return the first element found.
* @param key is the key to be matched.
* Default is the name of the element.
*/
GXMLElement* search(const char* key);
/**
* print all the elements.
*/
void printAll() const;
/**
* write the parsed tree (possibly with updated elements) back
* to a file as a well-formed XML.
*/
int writeStream(const char* file);
protected:
GXMLElement* _search(const char* key, GXMLElement* el);
void reportError();
int recursivePrintElement(ostream& o, int level, const GXMLElement* el) const;
};
#endif
Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999