[分享] 某知名手机平台的XML Parser源代码

Posted by gavinkwoe

    今天心情不错~ 分享一下小弟06年在某手机公司写的 .
虽然当时脑子里还没有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() || 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( "[ ]: 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, “”, 3) )
{
// Here, dispose version and coding infomation in document header
}
else if ( nLenTag == 14 && !strncmp(lpszTag, “-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


XML 生成类

Posted by dengwei

因为时常用到 ,但是有时是在 PHP4 环境、有时是在 PHP5 环境,并且有的环境中并没有编译 的扩展,所以没办法,为了让代码可以在任意环境运行,只好自己写了生成 的类,现在的功能仅支持生成 没有读取,暂时已经能较好的完成我的需求了,过段时间考虑重写一下,现在的代码 looks like too bad.

:)

使用时请把 部分代码给注释掉。

<?
/*
* $Id$
*/

// 程序名:.
// 用 途:根据传入内容生成 文件
// 作 者:邓威
// 日 期:2006-03-04
// 修 改:2006-03-13 邓威,错误修正
// 修 改:2006-07-07 邓威,重写代码,把原先的三个 改写成一个
error_reporting(E_ALL);

/* 例子一 */
$tree = new (”tree”);
$tree->type(””);
$tree->encoding(’GB2312′);
$tree->attributes( Array(’aaa’ => 111, ‘bbb’ => 222 ) );

$tree1 = new (”tree1″);
$tree1->tag(”tree1″);
$tree1->value(’aaaa’,true);

$tree2 = new (”tree2″,”123″);
$tree2->attribute(’abc’,'cba’);

$tree->addNode($tree1);
$tree->addNode($tree2);

header(’Content-Type: text/’);
echo $tree->display();

/* 例子二
$tree11 = new (”tagname”, ‘asdfasdf’);
echo $tree11->display();

$tree22 = new (’tagname1′,123123, array( ‘bb’ => 11 ));
echo $tree22->display();

$tree33 = new (’tagname3′);
echo $tree33->display();
*/


{
var $NodeTag = “”; // 当前对象的标签名
var $NodeType = “node”; // 共有四种类型:element, node,
var $NodeNodes = array(); // 子结点集合
var $NodeEncoding = “utf-8″; // 编码方式
var $NodeAttributes = array(); // 属性集合
var $NodeVersion = “1.0″; // 版本号
var $cdata = false; // 是否使用 cdata 分隔符
var $NodeValue = “”; // 结点值

/*
* 构造函数
*/

function ($strTag = NULL,$mixValue = NULL, $arrAttributes = NULL, $cdata = false)
{
if( !$strTag ) return false;
$this->tag($strTag);
if( is_array( $arrAttributes ) ) $this->attributes($arrAttributes);
if( method_exists($mixValue, “type”) && ( $mixValue->type() == “node” || $mixValue->type() == “element” ))
{
$this->addNode($mixValue);
}
else
{
if( is_string($mixValue) ) $this->cdata = true;
$this->value($mixValue, $cdata);
}
return $this;
}

/*
* 返回子节点数量
*/

function NodeCount()
{
return count($this->NodeNodes);
}

/*
* 文件版本号
* 现行的 文件中只有 1.0 版本
*/

function version($strVersion = NULL)
{
if( !$strVersion ) return $this->NodeVersion;
$this->NodeVersion = $strVersion;
return true;
}

/*
* 文件编码
*/

function encoding($strEncoding = NULL)
{
if( !$strEncoding ) return $this->NodeEncoding;
$this->NodeEncoding = $strEncoding;
return true;
}

/*
* 节点标签名
*/

function tag($strTag = NULL)
{
if( !$strTag ) return $this->NodeTag;
$this->NodeTag = $strTag;
return true;
}

/*
* 设置节点属性
*/

function attribute($strAttributeName = NULL, $mixAttributeValue = NULL)
{
if( !$strAttributeName ) return false;
// 设置属性
if( $mixAttributeValue )
{
$this->NodeAttributes[$strAttributeName] = $mixAttributeValue;
}
else // 删除属性
{
unset( $this->NodeAttributes[$strAttributeName] );
}
return true;
}

/*
* 设置节点属性集
*/

function attributes($arrAttributes = NULL)
{
if( !$arrAttributes ) return false;
if( !is_array($arrAttributes) ) return false;
$this->NodeAttributes = $arrAttributes;
return true;
}

/*
* 子节点集合
*/
function nodes($arrNodes = NULL)
{
if( !$arrNodes ) return $this->NodeNodes;
if( !is_array($arrNodes) ) return false;
$this->NodeNodes = $arrNodes;
return true;
}

/*
* 节点类型
*/

function type($strType = NULL)
{
if( !$strType ) return $this->NodeType;
if( $strType != “” && $strType != “node” && $strType != “element” ) return false;
$this->NodeType = $strType;
return true;
}

/*
* 加入新的节点对象
*/

function addNode($objNode = NULL)
{
if( !$objNode ) return false;
// lcl 是 local 的缩写,lcl_type 即是 local_type 局部变量的缩写
$lcl_type = $objNode->type();
if( $lcl_type != “element” && $lcl_type != “node” && $lcl_type != “” ) return false;
if( $lcl_type == “” ) $objNode->type(”node”);
// 加入新的节点对象
$this->NodeNodes[count($this->NodeNodes)] = $objNode;
return true;
}

/*
* 删除指定的节点
*/

function removeNodeByIndex($intIndex = 0)
{
return array_splice($this->NodeNodes, $intIndex-1, 1);
}

/*
* 删除指定的属性
*/

function removeAttributeByIndex($intIndex = 0)
{
return array_splice($this->NodeAttributes, $intIndex-1, 1);
}

/*
* 节点值
*/

function value($mixValue = ” , $cdata = false)
{
if( !$mixValue ) return $this->NodeValue;
if( $cdata ) $this->cdata = true;
$this->NodeValue = $mixValue;
return true;
}

/*
* 得到显示字符串
*/

function display($src_encoding = NULL, $intDepth = 0)
{
$strDisplay = “”;
$strAttribute = “”;

if( !$intDepth ) $intDepth = 0;

// 根节点
if( $this->type() == “” )
{
$strDisplay .= “<? version=\”" . $this->version() . “\” encoding=\”" . $this->encoding() . “\” ?>\n”;
}

// 缩近修正
$TAB_FIX = str_repeat( “\t” , $intDepth);

// 属性
if( ($lcl_count = count( $this->attributes() ) ) > 0 )
{
// 有属性
foreach( $this->NodeAttributes as $SingleAttribute => $SingleValue )
{
$strAttribute .= ‘ ‘ . $SingleAttribute . ‘=”‘ . $SingleValue . ‘”‘;
}
}

// 生成标签头
$strDisplay .= $TAB_FIX . “<” . $this->NodeTag . $strAttribute;

// 节点
if( ($lcl_counts = $this->NodeCount()) > 0 )
{
// 关闭标签头
$strDisplay .= “>\n”;
// 如果有子节点集
foreach( $this->NodeNodes as $SingleNode )
{
$strDisplay .= $SingleNode->display($src_encoding, $intDepth+1);
}
$strDisplay .= “</” . $this->NodeTag . “>\n”;
}
else
{
// 没有子节点
if( !$this->NodeValue )
{
// 节点没有值
// 关闭标签头
$strDisplay .= ” />”;
}
else
{
// 节点有值
$strDisplay .= “>\n”;
$strDisplay .= $TAB_FIX;

if( $this->cdata )
{
$strDisplay .= $TAB_FIX . “<![CDATA[" . ($src_encoding?iconv($src_encoding, $this->encoding() , $this->NodeValue):$this->NodeValue) . "]]>\n”;
}
else
{
$strDisplay .= $TAB_FIX . ($src_encoding?iconv($src_encoding, $this->encoding() , $this->NodeValue):$this->NodeValue) . “\n”;
}

$strDisplay .= $TAB_FIX . “</” . $this->NodeTag . “>\n”;
}

}
return $strDisplay;
}
}

?>