/****************************************************************************
 *   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