1. 规范化HTML文档函数canonHTML
功能:
对HTML文档进行简单规范化(canonicalization)
原型:
void
canonHTML( string & htmltext )
参数:
htmltext [in, out]
输入原始文档,输出正规化(normalized)文档。
说明:
参照W3C XML标准对文档良好格式和正规化(normalization)的定义,对HTML文档作如下的处理,为进一步的内容解析提供方便
* 文档起始字符为左尖括号“<”
* tag对象名称为小写
* tag对象属性(attribute)格式 name=”value” , 属性之间用一个空格符(#0x20)分隔
* 保留注释的内容 <!— 注释内容 -->
* 替换换行符号(#0x0A)
* 去除或替换空白为空格符(#0x20)
函数处理流程采用有限状态机形式,进行一次全文扫描
HTML元素的各个部分
* CONTENT, 形式 <tag>CONTENT</tag>
* TAG_BEGIN, 左尖括号 <
* TAG_END, 右尖括号 >
* START_TAG, 形式 <tag>
* END_TAG, 形式 </tag>
代码:
void
canonHTML( string & htmltext )
{
enum Enum_ElemPart
{
CONTENT,
TAG_BEGIN,
TAG_END,
START_TAG,
END_TAG,
ATTRIBUTE_NAME,
ATTRIBUTE_VALUE,
};
if ( htmltext.empty() )
return;
//string whitespaces( "\t\n\v\f\r " );
UInt32 src_sz = htmltext.size();
char *p_obj = new char[2 * src_sz + 1];
::memset( p_obj, 0, 2 * src_sz + 1 );
char *p_o = p_obj;
char *p_src = const_cast<char *>(htmltext.c_str());
for ( UInt32 pos = 0; pos < src_sz; ++pos )
{
if ( p_src[pos] == '<' )
break;
}
if ( pos == src_sz )
{
htmltext.resize( 0 );
delete [] p_obj;
return;
}
*(p_o++) = p_src[pos++];
Enum_ElemPart elem_part = TAG_BEGIN;
bool b_quote = false;
UInt32 pos_1 = 0;
while ( pos < src_sz )
{
switch ( p_src[pos] )
{
case '<' :
switch ( elem_part )
{
case TAG_BEGIN :
++pos;
break;
case ATTRIBUTE_VALUE :
while ( *(p_o - 1) == 0x20 )
{
*(--p_o) = '\0';
}
*(p_o++) = '"';
case START_TAG :
if ( *(p_o - 1) == 0x20 )
*(--p_o) = '\0';
if ( *(p_o - 1) == '=' )
{
*(p_o++) = '"';
*(p_o++) = '"';
}
case TAG_END :
case END_TAG :
case ATTRIBUTE_NAME :
*(p_o++) = '>';
case CONTENT :
*(p_o++) = p_src[pos++];
elem_part = TAG_BEGIN;
break;
}
break;
case '>' :
switch ( elem_part )
{
case TAG_BEGIN :
*(--p_o) = '\0';
elem_part = CONTENT;
break;
case ATTRIBUTE_VALUE :
while ( *(p_o - 1) == 0x20 )
{
*(--p_o) = '\0';
}
*(p_o++) = '"';
case START_TAG :
if ( *(p_o - 1) == 0x20 )
*(--p_o) = '\0';
if ( *(p_o - 1) == '=' )
{
*(p_o++) = '"';
*(p_o++) = '"';
}
case TAG_END :
case END_TAG :
case ATTRIBUTE_NAME :
elem_part = CONTENT;
case CONTENT :
*(p_o++) = p_src[pos++];
break;
}
break;
case '/' :
switch ( elem_part )
{
case TAG_BEGIN :
*(p_o++) = p_src[pos++];
elem_part = END_TAG;
break;
case START_TAG :
case ATTRIBUTE_NAME :
*(p_o++) = p_src[pos++];
elem_part = TAG_END;
break;
case ATTRIBUTE_VALUE :
case CONTENT :
*(p_o++) = p_src[pos++];
break;
default :
++pos;
break;
}
break;
case '=' :
switch ( elem_part )
{
case ATTRIBUTE_NAME :
elem_part = START_TAG;
case START_TAG :
if ( *(p_o - 1) == 0x20 )
--p_o;
*(p_o++) = p_src[pos++];
break;
case ATTRIBUTE_VALUE :
case CONTENT :
*(p_o++) = p_src[pos++];
break;
default :
++pos;
break;
}
break;
case '"' :
switch ( elem_part )
{
case START_TAG :
if ( *(p_o - 1) == '=' )
{
*(p_o++) = p_src[pos];
elem_part = ATTRIBUTE_VALUE;
b_quote = true;
}
++pos;
break;
case ATTRIBUTE_VALUE :
elem_part = START_TAG;
case CONTENT :
*(p_o++) = p_src[pos++];
break;
default :
++pos;
break;
}
break;
case '!' :
*(p_o++) = p_src[pos++];
if ( elem_part != TAG_BEGIN )
break;
for ( pos_1 = pos; pos_1 < src_sz; ++pos_1 )
{
if ( !isspace( p_src[pos_1] ) )
break;
}
pos = pos_1;
if ( pos < src_sz )
{
if ( p_src[pos] == '-'
&& p_src[pos + 1] == '-' )
{
*(p_o++) = p_src[pos++];
*(p_o++) = p_src[pos++];
for ( pos_1 = pos; pos_1 < src_sz; ++pos_1 )
{
*(p_o++) = p_src[pos_1];
if ( p_src[pos_1] == '-'
&& p_src[pos_1 + 1] == '-' )
{
*(p_o++) = p_src[++pos_1];
++pos_1;
elem_part = START_TAG;
break;
}
}
pos = pos_1;
if ( pos >= src_sz )
{
*(p_o++) = '>';
elem_part = CONTENT;
}
}
}
else
{
*(p_o++) = '>';
elem_part = CONTENT;
}
break;
case '\r' :
case '\n' :
if ( elem_part == CONTENT )
{
*(p_o++) = '\n';
++pos;
break;
}
case '\t' :
case '\v' :
case '\f' :
case 0x20 :
switch ( elem_part )
{
case START_TAG :
if ( *(p_o - 1) != 0x20
&& *(p_o - 1) != '=' )
*(p_o++) = 0x20;
++pos;
break;
case ATTRIBUTE_VALUE :
if ( !b_quote )
{
*(p_o++) = '"';
elem_part = START_TAG;
}
*(p_o++) = 0x20;
++pos;
break;
case ATTRIBUTE_NAME :
elem_part = START_TAG;
case CONTENT :
*(p_o++) = 0x20;
default :
++pos;
break;
}
break;
default:
switch ( elem_part )
{
case TAG_BEGIN :
*(p_o++) = lower_if_upper( p_src[pos++] );
elem_part = START_TAG;
break;
case START_TAG :
if ( *(p_o - 1) == 0x20 )
{
*(p_o++) = lower_if_upper( p_src[pos++] );
elem_part = ATTRIBUTE_NAME;
}
else
{
if ( *(p_o - 1) == '=' )
{
*(p_o++) = '"';
*(p_o++) = p_src[pos++];
elem_part = ATTRIBUTE_VALUE;
b_quote = false;
}
else
*(p_o++) = lower_if_upper( p_src[pos++] );
}
break;
case END_TAG :
case ATTRIBUTE_NAME :
*(p_o++) = lower_if_upper( p_src[pos++] );
break;
case ATTRIBUTE_VALUE :
case CONTENT :
*(p_o++) = p_src[pos++];
break;
default :
++pos;
break;
}
break;
}
}
*p_o = '\0';
htmltext.assign( p_obj );
delete [] p_obj;
}
相关引用函数:
char
lower_if_upper( const char ch )
{
if ( ch >= 'A' && ch <= 'Z' )
return ( ch + 0x20 ); // ch - 'A' + 'a' ;
else
return ch;
}