今天心情不错~ 分享一下小弟06年在某手机公司写的XML parser.
虽然当时脑子里还没有FSM的概念, 但代码逻辑还算清晰, 颇有成就感!
结构比较简单, 按DOM方式把指定文件解析成节点树, 另外提供几个简单的查找函数.
部分功能等完善, 过段时间再发一份功能比较完善的C++版本.
PLX_XMLParser.h
#if _MSC_VER > 1000
#pragma once
#endif
#ifndef __XMLPARSE_H
#define __XMLPARSE_H
#include
//////////////////////////////
// Configure
#define USE_INLINE_FUNCTION
#define USE_FILEBUFFER
//////////////////////////////
// Constants
typedef enum {
XMLERR_OK = 0×0,
XMLERR_EFILE, // failed to open file
XMLERR_ALRDOPEN, // already opened
XMLERR_EDOC,
XMLERR_EPARSE,
} XMLERR;
typedef enum {
NODETYPE_UNKN = 0×0,
NODETYPE_ELEM = 0×1,
NODETYPE_TEXT = 0×2,
NODETYPE_COMM = 0×4,
NODETYPE_INST = 0×8, // Not support
//NODETYPE_USEFUL = NODETYPE_ELEM|NODETYPE_TEXT,
//NODETYPE_ALL = NODETYPE_ELEM|NODETYPE_TEXT|NODETYPE_COMM|NODETYPE_INST,
} NODETYPE;
typedef enum {
DSTAT_UNOPEN = 0×0,
DSTAT_OPENED = 0×1,
} DOCSTAT;
typedef enum {
ISTAT_STOP = 0×0,
ISTAT_CONTINUE = 0×1,
ISTAT_PASS = 0×2,
} ITERSTAT;
enum { MAXLEN_BSTR = 256 };
//////////////////////////////
// Structures
struct tagBString
{
LONG m_lLength;
union {
CHAR m_paStr[1];
LPCSTR m_pszStr;
};
};
typedef struct tagBString BSTRING;
typedef struct tagBString *LPBSTRING;
typedef struct tagBString const *LPCBSTRING;
struct tagXMLAttrib;
typedef struct tagXMLAttrib XMLATTRIB;
typedef struct tagXMLAttrib *LPXMLATTRIB;
typedef struct tagXMLAttrib const *LPCXMLATTRIB;
struct tagXMLAttrib
{
LPBSTRING m_pbstrName;
LPBSTRING m_pbstrValue;
LPXMLATTRIB m_pNext;
};
struct tagXMLNode;
typedef struct tagXMLNode XMLNODE;
typedef struct tagXMLNode *LPXMLNODE;
typedef struct tagXMLNode const *LPCXMLNODE;
struct tagXMLNode
{
NODETYPE m_eNodeType;
LONG m_lDepth;
LPBSTRING m_pbstrTag;
LONG m_lChildNum;
LONG m_lChildNum_Elem;
LPXMLNODE m_pRoot;
LPXMLNODE m_pParent;
LPXMLNODE m_pFirstChild;
LPXMLNODE m_pLastChild;
LPXMLNODE m_pPrevSibling;
LPXMLNODE m_pNextSibling;
LONG m_lAttribNum;
LPXMLATTRIB m_pFirstAttrib;
};
struct tagXMLDocument
{
DOCSTAT m_eDocStat;
LPXMLNODE m_lpRootNode;
};
typedef struct tagXMLDocument XMLDOCUMENT;
typedef struct tagXMLDocument *LPXMLDOCUMENT;
typedef struct tagXMLDocument const *LPCXMLDOCUMENT;
//////////////////////////////
// Types
typedef ITERSTAT (CALLBACK *LPFNNODEPROC)( LPCXMLNODE pNode, LPVOID pvParam );
//////////////////////////////
// Macros
#if defined(USE_INLINE_FUNCTION)
#define BSTR_C( pBStr ) (&((pBStr)->m_paStr[0]))
#define BSTR_CAST( pvAnyType ) ((LPBSTRING)pvAnyType)
#define BSTR_LEN( pBStr ) ((pBStr)->m_lLength)
#define BSTR_ALLOC( pszStr ) AllocBString( pszStr, (NULL != (pszStr) ? ((LONG)strlen(pszStr)) : (0L)) )
#define BSTR_ALLOCEX( pszStr, nLen ) AllocBString( pszStr, (LONG)nLen )
#define BSTR_FREE( pBStr ) free( pBStr )
#define BSTR_SAFEFREE( pBStr ) if ( NULL != pBStr ) { free( pBStr ); pBStr = NULL; }
#define BSTR_EQUAL( pBStrL, pBStrR ) \
( (BSTR_LEN(pBStrL) == BSTR_LEN(pBStrR) && 0 == strcmp(BSTR_C(pBStrL), BSTR_C(pBStrL))) ? \
TRUE : FALSE )
#define BSTR_EQUAL_STATIC( pBStr, szStatic ) \
( (BSTR_LEN(pBStr) == (LONG)(sizeof(szStatic) - 1) && 0 == strcmp(BSTR_C(pBStr), szStatic)) ? \
TRUE : FALSE )
#define BSTR_EQUAL_CSTR( pBStr, pszStr ) \
( (BSTR_LEN(pBStr) == (LONG)strlen(pszStr) && 0 == strcmp(BSTR_C(pBStr), pszStr)) ? \
TRUE : FALSE )
#define XML_GetRootNode( pDoc ) ((NULL == (pDoc) || (pDoc)->m_eDocStat != DSTAT_OPENED) ? NULL : (pDoc)->m_lpRootNode)
#define XML_GetNodeType( pNode ) (NULL != (pNode) ? (pNode)->m_eNodeType : NODETYPE_UNKN)
#define XML_GetNodeDepth( pNode ) (NULL != (pNode) ? (pNode)->m_lDepth : (-1L))
#define XML_GetNodeParent( pNode ) (NULL != (pNode) ? (pNode)->m_pParent : NULL)
#define XML_GetNodeFirstChild( pNode ) (NULL != (pNode) ? (pNode)->m_pFirstChild : NULL)
#define XML_GetNodeLastChild( pNode ) (NULL != (pNode) ? (pNode)->m_pLastChild : NULL)
#define XML_GetNodeChildNum( pNode ) (NULL != (pNode) ? (pNode)->m_lChildNum : (0L))
#define XML_GetNodeChildNum_Elem( pNode ) (NULL != (pNode) ? (pNode)->m_lChildNum_Elem : (0L))
#define XML_GetNodePrevSibling( pNode ) (NULL != (pNode) ? (pNode)->m_pPrevSibling : NULL)
#define XML_GetNodeNextSibling( pNode ) (NULL != (pNode) ? (pNode)->m_pNextSibling : NULL)
#define XML_GetNodeTagName( pNode ) (NULL != (pNode) ? (pNode)->m_pbstrTag : NULL)
#define XML_GetNodeAttribNum( pNode ) (NULL != (pNode) ? (pNode)->m_lAttribNum : (0L))
#define XML_GetNodeFirstAttrib( pNode ) (NULL != (pNode) ? (pNode)->m_pFirstAttrib : NULL)
#define XML_GetNodeNextAttrib( pAttr ) (NULL != (pAttr) ? (pAttr)->m_pNext : NULL)
#define XML_GetAttribValueBString( pAttr ) (NULL != (pAttr) ? (pAttr)->m_pbstrValue) : NULL)
#define XML_GetAttribValueCString( pAttr ) (NULL != (pAttr) ? BSTR_C((pAttr)->m_pbstrValue) : NULL)
#define XML_GetAttribValueLong( pAttr ) (NULL != (pAttr) ? (LONG)strtol(BSTR_C((pAttr)->m_pbstrValue), NULL, 0) : (0L))
#define XML_GetAttribValueInt( pAttr ) (NULL != (pAttr) ? (int)strtol(BSTR_C((pAttr)->m_pbstrValue), NULL, 0) : (0))
#endif
//////////////////////////////
// Function prototypes
#if defined(__cplusplus)
extern “C” {
#endif
size_t strlen_when( LPCSTR lpszStr, CHAR ch );
size_t strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet );
LPCSTR strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet );
LPCSTR strchr_skipws( LPCSTR lpszStr );
LPBSTRING AllocBString( LPCSTR lpszStr, LONG lLen );
XMLERR XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve );
XMLERR XML_CloseDocument( LPXMLDOCUMENT pDoc );
LPXMLNODE XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen );
LPXMLATTRIB XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen );
LPXMLNODE XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL IncludeThis );
LONG XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam );
#if defined(__cplusplus)
} // extern “C” {
#endif
#endif // #ifndef __XMLPARSE_H
PLX_XMLParser.c
#include <assert.h>
#include <fcntl.h>
#include <io.h>
#if defined(DEBUG) || defined(_DEBUG)
#include <stdio.h>
#endif
#include “XMLParse.h”
//#pragma warning(disable:4305)
//////////////////////////////
// Configure
//#define USE_MEMORY_HEAP
#ifdef USE_FILEBUFFER // Whether use file system with os-layer buffer
#define INVALID_FILE_HANDLE ((int)-1)
#define FILE_HANDLE int
#define MODE_RDONLY (O_RDONLY)
#define FILE_OPEN(pszFile,mode) open( pszFile, mode )
#define FILE_READ(hFile,pbuf,size) read(hFile, (LPVOID)pbuf, size)
#define FILE_SEEK(hFile,off,pos) lseek( hFile, off, pos )
#define FILE_CLOSE(hFile) close( hFile )
#else
#define INVALID_FILE_HANDLE ((FILE *)NULL)
#define FILE_HANDLE FILE *
#define MODE_RDONLY (”r”)
#define FILE_OPEN(pszFile,mode) fopen( pszFile, mode )
#define FILE_READ(hFile,pbuf,size) fread((LPVOID)pbuf, size, 1, hFile)
#define FILE_SEEK(hFile,off,pos) fseek( hFile, off, pos )
#define FILE_CLOSE(hFile) fclose( hFile )
#endif
//////////////////////////////
// Constants
enum { MAXLEN_READBUF = 1024 };
typedef enum {
PSTAT_STOP = 0×0,
PSTAT_INITIAL,
PSTAT_FINAL,
PSTAT_DECL_BEG,
PSTAT_DECL_END,
PSTAT_ELEM_BEG,
PSTAT_ELEM_END,
PSTAT_TEXT_BEG,
PSTAT_TEXT_END,
PSTAT_CDATA_BEG,
PSTAT_CDATA_END,
PSTAT_COMM_BEG,
PSTAT_COMM_END,
PSTAT_ERROR,
} PARSESTAT;
//////////////////////////////
// Macros
#define ZERO_MEMORY(p, size) \
( memset((LPVOID)(p), 0×0, (size_t)size) )
#define is_WhiteSpace(ch) (((ch) == ‘ ‘ || (ch) == ‘\t’) ? TRUE : FALSE)
#define is_LineBreak(ch) (((ch) == ‘\r’ || (ch) == ‘\n’) ? TRUE : FALSE)
#define is_LeftBracket(ch) ((ch) == ‘<’ ? TRUE : FALSE)
#define is_RightBracket(ch) ((ch) == ‘>’ ? TRUE : FALSE)
#define is_BufferEmpty(ps) ((ps)->m_lReadCursor >= (ps)->m_lReadSize ? TRUE : FALSE)
#define get_BufferChar(ps) ((CHAR)((ps)->m_aReadBuf[(ps)->m_lReadCursor]))
#define is_FirstChild(pn) ((pn)->m_pPrevSibling == NULL ? TRUE : FALSE)
#define is_LastChild(pn) ((pn)->m_pNextSibling == NULL ? TRUE : FALSE)
//////////////////////////////
// Structures
struct tagXMLParseStat
{
PARSESTAT m_eParseStat;
LONG m_lDepth;
LPXMLNODE m_pRootNode;
LPXMLNODE m_pLastNode;
FILE_HANDLE m_hOpenFile;
LONG m_lFileCursor;
LONG m_lFileLength;
LONG m_lLineNo;
LONG m_lReadCursor;
LONG m_lReadSize;
BYTE m_aReadBuf[MAXLEN_READBUF];
};
typedef struct tagXMLParseStat XMLPARSESTAT;
typedef struct tagXMLParseStat *LPXMLPARSESTAT;
typedef struct tagXMLParseStat const *LPCXMLPARSESTAT;
struct tagXMLIterator
{
LONG m_lCount;
LPFNNODEPROC m_pfnProc;
LPVOID m_pvParam;
LPXMLNODE m_pStation;
};
typedef struct tagXMLIterator XMLITERFATOR;
typedef struct tagXMLIterator *LPXMLITERFATOR;
typedef struct tagXMLIterator const *LPCXMLITERFATOR;
/*struct tagMemoryPage
{
LONG lGranu ;
LONG lSize;
LPVOID pvPage;
BYTE bUseFlags[1];
};
typedef struct tagMemoryPage MEMORYPAGE;
typedef struct tagMemoryPage *LPMEMORYPAGE;
typedef struct tagMemoryPage const *LPCMEMORYPAGE;*/
//////////////////////////////
// Function prototypes
#if defined(__cplusplus)
extern “C” {
#endif
static void XML_FreeNodeTree( LPXMLNODE pNode );
static void XML_FreeAttribList( LPXMLATTRIB pAttrib );
static void XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator );
static BOOL XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam );
static BOOL Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult );
static int Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf );
static BOOL Parser_ReadStream( LPXMLPARSESTAT pParseStat );
static void Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static BOOL Parser_OnFinal( LPXMLPARSESTAT pParseStat );
static BOOL Parser_OnError( LPXMLPARSESTAT pParseStat );
//#if defined(USE_MEMORY_HEAP)
//static LPVOID MemoryHeap_Create( LONG lInitialGranu, LONG lInitialSize );
//static BOOL MemoryHeap_Destroy( LPVOID );
//static LPVOID MemoryHeap_Alloc( void );
//static void MemoryHeap_Free( LPVOID pvBlock );
//#endif
#if defined(__cplusplus)
} // extern “C” {
#endif
//////////////////////////////
// Function implementations
#if defined(__cplusplus)
extern “C” {
#endif
/*********************************************************************\
* Function: strlen_when
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
size_t strlen_when( LPCSTR lpszStr, CHAR ch )
{
register size_t nLen;
assert( NULL != lpszStr );
for ( nLen = 0; *lpszStr != ch && *lpszStr != ‘\0′; lpszStr++, nLen++ )
;
return nLen;
}
/*********************************************************************\
* Function: strlen_notin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
size_t strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet )
{
register size_t nLen;
assert( NULL != lpszStr );
for ( nLen = 0; *lpszStr != ‘\0′ && NULL == strchr(lpszSet, *lpszStr); lpszStr++, nLen++ )
;
return nLen;
}
/*********************************************************************\
* Function: strchr_notin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPCSTR strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet )
{
assert( NULL != lpszStr );
for ( ; *lpszStr != ‘\0′ && NULL == strchr(lpszSet, *lpszStr); lpszStr++ )
;
return lpszStr;
}
/*********************************************************************\
* Function: strchr_skipws
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPCSTR strchr_skipws( LPCSTR lpszStr )
{
assert( NULL != lpszStr );
for ( ; *lpszStr != ‘\0′ && is_WhiteSpace(*lpszStr); lpszStr++ )
;
return lpszStr;
}
/*********************************************************************\
* Function: AllocBString
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPBSTRING AllocBString( LPCSTR lpszStr, LONG lLen )
{
LPBSTRING pBStr = (LPBSTRING)malloc( sizeof(LONG) + lLen + 1 );
assert( NULL != pBStr );
pBStr->m_lLength = lLen;
strncpy( &pBStr->m_paStr[0], lpszStr, lLen );
pBStr->m_paStr[lLen] = ‘\0′;
return pBStr;
}
/*********************************************************************\
* Function: XML_OpenDocument
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
XMLERR XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve )
{
BOOL bRet;
FILE_HANDLE hFile;
XMLPARSESTAT xmlParseStat;
assert( NULL != pDoc );
assert( NULL != lpszFileName );
if ( pDoc->m_eDocStat == DSTAT_OPENED )
return XMLERR_ALRDOPEN;
ZERO_MEMORY( &xmlParseStat, sizeof(XMLPARSESTAT) );
hFile = FILE_OPEN( lpszFileName, MODE_RDONLY );
if ( INVALID_FILE_HANDLE == hFile )
return XMLERR_EFILE;
xmlParseStat.m_hOpenFile = hFile;
xmlParseStat.m_lFileCursor = 0;
xmlParseStat.m_lFileLength = FILE_SEEK( hFile, 0, SEEK_END );
FILE_SEEK( hFile, 0, SEEK_SET );
xmlParseStat.m_lDepth = 0;
xmlParseStat.m_lLineNo = 1;
bRet = Parser_RoutineStart( &xmlParseStat, pDoc );
if ( FALSE == bRet )
{
FILE_CLOSE( hFile );
return XMLERR_EPARSE;
}
pDoc->m_eDocStat = DSTAT_OPENED;
pDoc->m_lpRootNode = xmlParseStat.m_pRootNode;
FILE_CLOSE( hFile );
return XMLERR_OK;
}
/*********************************************************************\
* Function: XML_CloseDocument
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
XMLERR XML_CloseDocument( LPXMLDOCUMENT pDoc )
{
if ( NULL != pDoc && pDoc->m_eDocStat == DSTAT_OPENED )
{
XML_FreeNodeTree( pDoc->m_lpRootNode );
pDoc->m_lpRootNode = NULL;
pDoc->m_eDocStat = DSTAT_UNOPEN;
}
return XMLERR_OK;
}
/*********************************************************************\
* Function: Parser_GetTagString
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
int Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf )
{
int nLen;
CHAR ch;
CHAR chTerm;
BOOL bInclude;
// Should to ensure barket match Here!
nLen = 0;
for ( ;; )
{
if ( is_BufferEmpty(pParseStat) && FALSE == Parser_ReadStream(pParseStat) )
goto __RET;
ch = get_BufferChar(pParseStat);
if ( ch == ‘\n’ )
pParseStat->m_lLineNo++;
if ( !is_WhiteSpace(ch) && !is_LineBreak(ch) )
break;
pParseStat->m_lReadCursor++;
}
if ( is_LeftBracket(ch) )
{
chTerm = ‘>’;
bInclude = TRUE;
}
else
{
chTerm = ‘<’;
bInclude = FALSE;
}
for ( ;; )
{
if ( is_BufferEmpty(pParseStat) && FALSE == Parser_ReadStream(pParseStat) )
break;
ch = get_BufferChar(pParseStat);
if ( ch == ‘\n’ )
pParseStat->m_lLineNo++;
if ( ch == chTerm )
{
if ( FALSE != bInclude )
{
lpszBuf[nLen++] = chTerm;
pParseStat->m_lReadCursor++;
}
break;
}
lpszBuf[nLen++] = ch;
pParseStat->m_lReadCursor++;
}
__RET:
lpszBuf[nLen] = ‘\0′;
return nLen;
}
/*********************************************************************\
* Function: Parser_ReadStream
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_ReadStream( LPXMLPARSESTAT pParseStat )
{
size_t nSize;
pParseStat->m_lReadCursor = 0;
pParseStat->m_lReadSize = 0;
nSize = FILE_READ( pParseStat->m_hOpenFile, (LPVOID)&pParseStat->m_aReadBuf[0], MAXLEN_READBUF );
if ( nSize <= 0 )
return FALSE;
pParseStat->m_lReadSize = (LONG)nSize;
pParseStat->m_lFileCursor += (LONG)nSize;
return TRUE;
}
/*********************************************************************\
* Function: Parser_RoutineStart
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult )
{
BOOL bRet;
CHAR szTag[256];
assert( NULL != pParseStat );
pParseStat->m_eParseStat = PSTAT_INITIAL;
while ( pParseStat->m_eParseStat != PSTAT_STOP )
{
switch ( pParseStat->m_eParseStat )
{
case PSTAT_INITIAL: Parser_OnInitial( pParseStat, &szTag[0] ); break;
case PSTAT_DECL_BEG: Parser_OnDeclBegin( pParseStat, &szTag[0] ); break;
case PSTAT_DECL_END: Parser_OnDeclEnd( pParseStat, &szTag[0] ); break;
case PSTAT_ELEM_BEG: Parser_OnElemBegin( pParseStat, &szTag[0] ); break;
case PSTAT_ELEM_END: Parser_OnElemEnd( pParseStat, &szTag[0] ); break;
case PSTAT_TEXT_BEG: Parser_OnTextBegin( pParseStat, &szTag[0] ); break;
case PSTAT_TEXT_END: Parser_OnTextEnd( pParseStat, &szTag[0] ); break;
case PSTAT_CDATA_BEG: Parser_OnCDATABegin( pParseStat, &szTag[0] ); break;
case PSTAT_CDATA_END: Parser_OnCDATAEnd( pParseStat, &szTag[0] ); break;
case PSTAT_COMM_BEG: Parser_OnCommBegin( pParseStat, &szTag[0] ); break;
case PSTAT_COMM_END: Parser_OnCommEnd( pParseStat, &szTag[0] ); break;
case PSTAT_FINAL: bRet = Parser_OnFinal( pParseStat ); break;
case PSTAT_ERROR: bRet = Parser_OnError( pParseStat ); break;
default:
assert( !”Unknown parsing status!” );
break;
}
}
return bRet;
}
/*********************************************************************\
* Function: Parser_OnInitial
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int nLen;
assert( NULL != lpszTag );
lpszTag[0] = ‘\0′;
nLen = Parser_GetTagString( pParseStat, lpszTag );
if ( nLen <= 0 )
{
pParseStat->m_eParseStat = PSTAT_STOP;
return;
}
if ( lpszTag[0] == ‘<’ )
{
if ( lpszTag[1] == ‘?’)
{
pParseStat->m_eParseStat = PSTAT_DECL_BEG;
}
else if ( !strncmp(&lpszTag[1], “!–”, 3) )
{
pParseStat->m_eParseStat = PSTAT_COMM_BEG;
}
else if ( lpszTag[1] == ‘/’ )
{
pParseStat->m_eParseStat = PSTAT_ELEM_END;
}
else if ( isalpha(lpszTag[1]) )
{
pParseStat->m_eParseStat = PSTAT_ELEM_BEG;
}
else if ( !strncmp(&lpszTag[1], “![CDATA[", 8) )
{
pParseStat->m_eParseStat = PSTAT_CDATA_BEG;
}
else
{
pParseStat->m_eParseStat = PSTAT_ERROR;
}
}
else if ( NULL != pParseStat->m_pLastNode )
{
pParseStat->m_eParseStat = PSTAT_TEXT_BEG;
}
else
{
pParseStat->m_eParseStat = PSTAT_ERROR;
}
}
/*********************************************************************\
* Function: Parser_OnFinal
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_OnFinal( LPXMLPARSESTAT pParseStat )
{
pParseStat->m_eParseStat = PSTAT_STOP;
return TRUE;
}
/*********************************************************************\
* Function: Parser_OnError
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_OnError( LPXMLPARSESTAT pParseStat )
{
XML_FreeNodeTree( pParseStat->m_pRootNode );
pParseStat->m_pRootNode = NULL;
pParseStat->m_eParseStat = PSTAT_STOP;
TRACE( "[Xml Parser]: Syntax error @ %s #%ld.\n”, “”, pParseStat->m_lLineNo);
return FALSE;
}
/*********************************************************************\
* Function: Parser_OnDeclBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int nLenTag;
if ( NULL != pParseStat->m_pRootNode )
{
pParseStat->m_eParseStat = PSTAT_ERROR;
return;
}
lpszTag = (LPSTR)strchr_skipws( (LPCSTR)(lpszTag + 2) );
if ( lpszTag == ‘\0′ )
{
pParseStat->m_eParseStat = PSTAT_ERROR;
return;
}
nLenTag = (int)strlen_notin(lpszTag, ” \t\r\n>”);
if ( nLenTag == 3 && !strncmp(lpszTag, “xml”, 3) )
{
// Here, dispose version and coding infomation in XML document header
}
else if ( nLenTag == 14 && !strncmp(lpszTag, “xml-stylesheet”, 3) )
{
// Unsupport
}
else
{
// Unknown declaretion
}
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnDeclEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
// Do noting
}
/*********************************************************************\
* Function: Parser_OnElemBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int nLenTag;
int nLenValue;
LPSTR lpszValue;
LPXMLNODE pNode;
LPXMLATTRIB pAttrib;
LPXMLATTRIB pPrevAttr;
assert( is_LeftBracket(lpszTag[0]) );
// Multi-root node is not supproted
if ( 0 == pParseStat->m_lDepth && NULL != pParseStat->m_pRootNode )
goto __ERROR;
pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));
if ( NULL == pNode )
goto __ERROR;
ZERO_MEMORY( pNode, sizeof(XMLNODE) );
pNode->m_eNodeType = NODETYPE_ELEM;
pNode->m_lDepth = pParseStat->m_lDepth;
if ( NULL != pParseStat->m_pLastNode )
{
assert( pNode->m_lDepth >= pParseStat->m_pLastNode->m_lDepth );
if ( pNode->m_lDepth > pParseStat->m_pLastNode->m_lDepth ) // new child
{
pNode->m_pParent = pParseStat->m_pLastNode;
pParseStat->m_pLastNode->m_pFirstChild = pNode;
}
else if ( pNode->m_lDepth == pParseStat->m_pLastNode->m_lDepth ) // new sibling
{
pNode->m_pParent = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_pLastNode->m_pNextSibling = pNode;
pNode->m_pPrevSibling = pParseStat->m_pLastNode;
}
if ( NULL != pNode->m_pParent )
{
pNode->m_pParent->m_lChildNum++;
pNode->m_pParent->m_lChildNum_Elem++;
}
}
if ( NULL == pParseStat->m_pRootNode )
{
pParseStat->m_pRootNode = pNode;
}
pNode->m_pRoot = pParseStat->m_pRootNode;
pParseStat->m_pLastNode = pNode;
lpszTag++;
nLenTag = (int)strlen_notin(lpszTag, ” \t\r\n>”);
if ( nLenTag <= 0 )
goto __ERROR;
pNode->m_pbstrTag = BSTR_ALLOCEX(lpszTag, nLenTag);
if ( NULL == pNode->m_pbstrTag )
goto __ERROR;
lpszTag = (LPSTR)(lpszTag + nLenTag);
for ( pPrevAttr = NULL;; )
{
lpszTag = (LPSTR)strchr_skipws( lpszTag );
if ( is_RightBracket(*lpszTag) )
{
pParseStat->m_lDepth++; // Move down one layer
pParseStat->m_eParseStat = PSTAT_INITIAL;
break;
}
else if ( !strncmp(lpszTag, “/>”, 2) )
{
//pParseStat->m_lDepth–; //
pParseStat->m_eParseStat = PSTAT_INITIAL;
break;
}
nLenTag = (int)strlen_when( lpszTag, ‘=’ );
if ( nLenTag <= 0 )
goto __ERROR;
lpszValue = strchr( (LPCSTR)(lpszTag + nLenTag), ‘\”‘ );
if ( NULL == lpszValue )
goto __ERROR;
lpszValue++;
nLenValue = (int)strlen_when( lpszValue, ‘\”‘ );
//if ( nLenValue <= 0 )
// goto __ERROR;
pAttrib = (LPXMLATTRIB)malloc(sizeof(XMLATTRIB));
if ( NULL == pAttrib )
goto __ERROR;
ZERO_MEMORY( pAttrib, sizeof(XMLATTRIB) );
pAttrib->m_pbstrName = BSTR_ALLOCEX( lpszTag, nLenTag );
pAttrib->m_pbstrValue = BSTR_ALLOCEX( lpszValue, nLenValue );
if ( NULL == pAttrib->m_pbstrName || NULL == pAttrib->m_pbstrValue )
goto __ERROR;
if ( NULL == pNode->m_pFirstAttrib )
pNode->m_pFirstAttrib = pAttrib;
if ( NULL != pPrevAttr )
pPrevAttr->m_pNext = pAttrib;
pPrevAttr = pAttrib;
pNode->m_lAttribNum++;
lpszTag = lpszValue + nLenValue + 1;
}
return;
__ERROR:
XML_FreeNodeTree( pNode );
pParseStat->m_eParseStat = PSTAT_ERROR;
}
/*********************************************************************\
* Function: Parser_OnElemEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_lDepth–;
if ( NULL != pParseStat->m_pLastNode )
{
if ( NULL != pParseStat->m_pLastNode->m_pParent )
pParseStat->m_pLastNode->m_pParent->m_pLastChild = pParseStat->m_pLastNode;
if ( pParseStat->m_pLastNode->m_lDepth > pParseStat->m_lDepth )
pParseStat->m_pLastNode = pParseStat->m_pLastNode->m_pParent;
}
if ( 0 == pParseStat->m_lDepth )
pParseStat->m_eParseStat = PSTAT_FINAL;
else
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnTextBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
LPXMLNODE pNode;
pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));
if ( NULL == pParseStat->m_pLastNode )
goto __ERROR;
ZERO_MEMORY( pNode, sizeof(XMLNODE) );
pNode->m_eNodeType = NODETYPE_TEXT;
pNode->m_lDepth = pParseStat->m_lDepth;
if ( NULL != pParseStat->m_pLastNode )
{
assert( pNode->m_lDepth >= pParseStat->m_pLastNode->m_lDepth );
if ( pNode->m_lDepth > pParseStat->m_pLastNode->m_lDepth )
{
pNode->m_pParent = pParseStat->m_pLastNode;
pParseStat->m_pLastNode->m_pFirstChild = pNode;
}
else if ( pNode->m_lDepth == pParseStat->m_pLastNode->m_lDepth )
{
pNode->m_pParent = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_pLastNode->m_pNextSibling = pNode;
pNode->m_pPrevSibling = pParseStat->m_pLastNode;
}
if ( NULL != pNode->m_pParent )
pNode->m_pParent->m_lChildNum++;
pNode->m_pRoot = pParseStat->m_pLastNode->m_pRoot;
}
pParseStat->m_pLastNode = pNode;
pNode->m_pbstrTag = BSTR_ALLOC(lpszTag);
if ( NULL == pNode->m_pbstrTag )
goto __ERROR;
pParseStat->m_lDepth++; // Move down one layer
pParseStat->m_eParseStat = PSTAT_TEXT_END;
return;
__ERROR:
XML_FreeNodeTree( pNode );
pParseStat->m_eParseStat = PSTAT_ERROR;
}
/*********************************************************************\
* Function: Parser_OnTextEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
// Move up one layer
pParseStat->m_lDepth–;
if ( NULL != pParseStat->m_pLastNode &&
pParseStat->m_pLastNode->m_lDepth > pParseStat->m_lDepth )
pParseStat->m_pLastNode = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnCommBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnCommEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
}
/*********************************************************************\
* Function: Parser_OnCDATABegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_eParseStat = PSTAT_INITIAL;
// Should convert to text here
}
/*********************************************************************\
* Function: Parser_OnCDATAEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
}
/*********************************************************************\
* Function: XML_IterateTree
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator )
{
register ITERSTAT eStat;
if ( NULL != pTree )
{
pIterator->m_pStation = pTree;
eStat = pIterator->m_pfnProc( pTree, pIterator->m_pvParam );
if ( eStat == ISTAT_STOP )
return;
if ( eStat != ISTAT_PASS )
pIterator->m_lCount++;
XML_IterateTree( pTree->m_pFirstChild, pIterator );
XML_IterateTree( pTree->m_pNextSibling, pIterator );
}
}
/*********************************************************************\
* Function: XML_ForEachNode
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LONG XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam )
{
XMLITERFATOR iter;
assert( NULL != pDoc );
assert( NULL != pfnNodeProc );
if ( pDoc->m_eDocStat == DSTAT_UNOPEN || (NULL != pStartPoint && pStartPoint->m_pRoot != pDoc->m_lpRootNode) )
return 0;
iter.m_lCount = 0;
iter.m_pStation = NULL;
iter.m_pvParam = pvParam;
iter.m_pfnProc = pfnNodeProc;
pStartPoint = (NULL == pStartPoint ? pDoc->m_lpRootNode : pStartPoint);
XML_IterateTree( pStartPoint, &iter );
return iter.m_lCount;
}
/*********************************************************************\
* Function: XMLCmpNode_EqualTag
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
ITERSTAT XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam )
{
if ( FALSE != BSTR_EQUAL(pNode->m_pbstrTag, BSTR_CAST(pvParam)) )
return ISTAT_STOP;
else
return ISTAT_CONTINUE;
}
/*********************************************************************\
* Function: XML_GetNode
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLNODE XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen )
{
BSTRING bStr;
XMLITERFATOR iter;
assert( NULL != lpszTag );
assert( NULL != pDoc );
if ( pDoc->m_eDocStat == DSTAT_UNOPEN || pStartPoint->m_pRoot != pDoc->m_lpRootNode )
return NULL;
bStr.m_lLength = lLen;
bStr.m_pszStr = lpszTag;
iter.m_lCount = 0;
iter.m_pfnProc = &XMLCmpNode_EqualTag;
iter.m_pStation = NULL;
iter.m_pvParam = (LPVOID)&bStr;
pStartPoint = (NULL == pStartPoint ? pDoc->m_lpRootNode : pStartPoint);
XML_IterateTree( pStartPoint, &iter );
return (iter.m_pStation);
}
/*********************************************************************\
* Function: XML_GetNodeAttrib
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLATTRIB XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen )
{
BSTRING bStr;
LPXMLATTRIB pAttrib;
assert( NULL != lpszAttr );
assert( NULL != pNode );
bStr.m_lLength = lLen;
bStr.m_pszStr = lpszAttr;
for ( pAttrib = XML_GetNodeFirstAttrib(pNode); NULL != pAttrib; pAttrib = XML_GetNodeNextAttrib(pAttrib) )
{
if ( FALSE != BSTR_EQUAL(pAttrib->m_pbstrName, &bStr) )
break;
}
return pAttrib;
}
/*********************************************************************\
* Function: XML_GetNodeSibling
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLNODE XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL bIncludeThis )
{
BSTRING bStr;
assert( NULL != lpszTag );
assert( NULL != pNode );
bStr.m_lLength = lLen;
bStr.m_pszStr = lpszTag;
if ( FALSE != bIncludeThis && FALSE != BSTR_EQUAL(pNode->m_pbstrTag, &bStr) )
return pNode;
for ( pNode = XML_GetNodeNextSibling(pNode); NULL != pNode; pNode = XML_GetNodeNextSibling(pNode) )
{
if ( FALSE != BSTR_EQUAL(pNode->m_pbstrTag, &bStr) )
break;
}
return pNode;
}
/*********************************************************************\
* Function: XML_FreeNodeTree
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_FreeNodeTree( LPXMLNODE pNode )
{
if ( NULL != pNode )
{
BSTR_FREE( pNode->m_pbstrTag );
XML_FreeAttribList( pNode->m_pFirstAttrib );
if ( is_FirstChild(pNode) && NULL != pNode->m_pParent )
pNode->m_pParent->m_pFirstChild = pNode->m_pNextSibling;
if ( NULL != pNode->m_pNextSibling )
pNode->m_pNextSibling->m_pPrevSibling = pNode->m_pPrevSibling;
if ( NULL != pNode->m_pPrevSibling )
pNode->m_pPrevSibling->m_pNextSibling = pNode->m_pNextSibling;
XML_FreeNodeTree( pNode->m_pFirstChild );
XML_FreeNodeTree( pNode->m_pNextSibling );
free( pNode );
}
}
/*********************************************************************\
* Function: XML_FreeAttribList
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_FreeAttribList( LPXMLATTRIB pAttrib )
{
LPXMLATTRIB pNext;
while ( NULL != pAttrib )
{
pNext = pAttrib->m_pNext;
BSTR_FREE( pAttrib->m_pbstrName );
BSTR_FREE( pAttrib->m_pbstrValue );
free( pAttrib );
pAttrib = pNext;
}
}
#if defined(__cplusplus)
} // extern “C” {
#endif