Cmarkup自动缩进的实现(二种方法)
Cmarkup自动缩进的实现(2种方法)
前阵子项目中需要使用XML文件来保存日志,便使用了CMarkup这个类,
可惜保存的时候无法格式化,就是不能自动缩进(但是已经分行),如下:
<RootElem>
<Elem1>
<Elem2/>
</Elem1>
<Elem3/>
</RootElem>
实在是不好阅读,当然实际上项目中需要的并不是让用户自己去看XML格式的文件,而是将日志文件读出来在程序界面上解释给用户看的,但是仅仅为了乐趣也可以一试。
目前实现了2种方法,第一种是添加了一个SaveAndFormat函数来在保存XML文档的时候为每行添加缩进字符,可惜效率低下,特别是元素越来越多的时候,甚至有保存一条新日志都需要个3、4秒。
所以就想在AddElem的时候直接加入缩进字符(只需要修改三个函数):
——————————————————再分割线——————————————————————
而要在AddItem的时候加入缩进,只需要修改三个函数
x_GetTagName
x_AddElem
x_InsertNew
只需要注意我添加和修改的部分
ps.当然也还需要前面的缩进字符定义x_INDENT 和 获取节点等级的函数x_GetNodeLevel
前阵子项目中需要使用XML文件来保存日志,便使用了CMarkup这个类,
可惜保存的时候无法格式化,就是不能自动缩进(但是已经分行),如下:
<RootElem>
<Elem1>
<Elem2/>
</Elem1>
<Elem3/>
</RootElem>
实在是不好阅读,当然实际上项目中需要的并不是让用户自己去看XML格式的文件,而是将日志文件读出来在程序界面上解释给用户看的,但是仅仅为了乐趣也可以一试。
目前实现了2种方法,第一种是添加了一个SaveAndFormat函数来在保存XML文档的时候为每行添加缩进字符,可惜效率低下,特别是元素越来越多的时候,甚至有保存一条新日志都需要个3、4秒。
所以就想在AddElem的时候直接加入缩进字符(只需要修改三个函数):
// 在Markup.h 头文件中添加如下定义
//*///////////////////////////////////////////////////////////////////
// Add by CLin
// 定义缩进标识符(此处为2个空格符, 也可以使用制表符\t)
#define x_INDENT MCD_T(" ") // can be \t or empty
//*///////////////////////////////////////////////////////////////////
//*///////////////////////////////////////////////////////////////
// Add by CLin (递归部分)
// 保存并格式化函数
bool SaveAndFormat( MCD_CSTR_FILENAME szFileName );
//*///////////////////////////////////////////////////////////////
//*///////////////////////////////////////////////////////////////
// Add by CLin (递归部分)
// 格式化函数以及节点分级函数
bool x_FormatDoc( MCD_STR &strDoc, UINT iLevel );
int x_GetNodeLevel( int iNodePos );
//*///////////////////////////////////////////////////////////////
/////////////-------------分割线-------------//////////////////////
//Markup.cpp 文件中添加如下函数实现
//*///////////////////////////////////////////////////////////////
// Add by CLin (递归部分)
// 格式化文档函数(使用递归, 当文档变大时, 效率低下)
bool CMarkup::x_FormatDoc( MCD_STR &strDoc, UINT iLevel )
{
if ( MCD_STRISEMPTY( strDoc) )
return true;
MCD_STR strSepaDoc;
MCD_STR strFormatted;
MCD_STR strRow;
MCD_STR strItem;
MCD_STR strIndent;
strSepaDoc = strDoc;
strFormatted.Empty();
strRow.Empty();
strItem.Empty();
strIndent.Empty();
// 根据节点等级计算缩进量
for (int iInd=0;iInd<(int)iLevel; iInd++)
strIndent += x_INDENT;
// 缩进
for (int iTemp=0; iTemp<MCD_STRLENGTH(strSepaDoc); iTemp++)
{
// 截取到一行
if (strSepaDoc[iTemp] != '\r' && strSepaDoc[iTemp+1] != '\n')
continue;
strRow = strSepaDoc.Left(iTemp + 2);
strSepaDoc = strSepaDoc.Mid(iTemp + 2);
// 获取元素名
sscanf(strRow, "<%s>", strItem.GetBuffer(128));
strItem.ReleaseBuffer();
if (strItem.Find(">") != -1)
strItem = strItem.Left(strItem.Find(">"));
// 如果该行已经格式化则不做处理
if (strRow.Find("<") > 0)
strFormatted += strRow;
else
strFormatted += strIndent + strRow;
// 该元素无子元素
if (strRow.Find("</") != -1 || strRow.Find("/>") != -1)
{
iTemp = 0;
continue;
}
// 该元素有子元素, 则截取子元素集合递归处理
iTemp = strSepaDoc.Find("</" + strItem + ">");
strRow = strSepaDoc.Left(iTemp);
strSepaDoc = strSepaDoc.Mid(iTemp);
x_FormatDoc(strRow, iLevel+1);
strFormatted += strRow;
iTemp = 0;
continue;
}
strDoc = strFormatted;
return true;
}
// 获取节点等级
int CMarkup::x_GetNodeLevel( int iNodePos )
{
if ( iNodePos <= 0)
return -1;
if ( iNodePos == 1 )
return 0;
int iLevel;
iLevel = 0;
while ( iNodePos != 1 )
{
iNodePos = x_GetParent( iNodePos );
iLevel++;
}
return iLevel;
}
//*///////////////////////////////////////////////////////////////
//*///////////////////////////////////////////////////////////////
// Add by CLin (递归部分)
// 保存并格式化函数
bool CMarkup::SaveAndFormat( MCD_CSTR_FILENAME szFileName )
{
if ( m_nDocFlags & (MDF_READFILE|MDF_WRITEFILE) )
return false;
MCD_STR strFormattedDoc;
MCD_STR strDocHeader;
MCD_STR strDocBody;
strFormattedDoc = m_strDoc;
strDocHeader = strFormattedDoc.Left( strFormattedDoc.Find("?>") + 4 );
strDocBody = strFormattedDoc.Mid( strFormattedDoc.Find("?>") + 4);
if ( ! x_FormatDoc( strDocBody, 0 ) )
return false;
strFormattedDoc = strDocHeader + strDocBody;
return WriteTextFile( szFileName, strFormattedDoc, &m_strResult, &m_nDocFlags );
}
//*///////////////////////////////////////////////////////////////
——————————————————再分割线——————————————————————
而要在AddItem的时候加入缩进,只需要修改三个函数
x_GetTagName
x_AddElem
x_InsertNew
只需要注意我添加和修改的部分
ps.当然也还需要前面的缩进字符定义x_INDENT 和 获取节点等级的函数x_GetNodeLevel
// 此函数作用是获取指定元素的元素名
MCD_STR CMarkup::x_GetTagName( int iPos ) const