在处理XML或HTML文本时,如果只需要找到某个词、标签或属性,使用完整的DOM编译器或SAX解析器可能过于复杂。此时,使用一个轻量级的标记扫描器是一个更好的选择。下面介绍的markup::scanner
就是这样一个工具,它具有以下特点:
最好的解释方式是通过示例。首先,需要为扫描器声明一个输入流。以下是一个基于字符串的简单流示例:
struct str_istream : public markup::instream {
const char* p;
const char* end;
str_istream(const char* src) : p(src), end(src + strlen(src)) {}
virtual wchar_t get_char() {
return p < end ? *p++ : 0;
}
};
以上代码定义了一个简单的字符串输入流。接下来,将编写一个程序,打印出输入HTML中的所有标记:
int main(int argc, char* argv[]) {
str_istream si(
" Begin & back
"
""
);
markup::scanner sc(si);
bool in_text = false;
while (true) {
int t = sc.get_token();
switch (t) {
case markup::scanner::TT_ERROR:
printf("ERROR\n");
break;
case markup::scanner::TT_EOF:
printf("EOF\n");
goto FINISH;
case markup::scanner::TT_TAG_START:
printf("TAG START:%s\n", sc.get_tag_name());
break;
case markup::scanner::TT_TAG_END:
printf("TAG END:%s\n", sc.get_tag_name());
break;
case markup::scanner::TT_ATTR:
printf("\tATTR:%s=%S\n", sc.get_attr_name(), sc.get_value());
break;
case markup::scanner::TT_WORD:
case markup::scanner::TT_SPACE:
printf("{%S}\n", sc.get_value());
break;
}
}
FINISH:
printf("--------------------------\n");
return 0;
}
如所见,主要的工作方法是markup::scanner::get_token()
。它扫描输入流并返回markup::scanner::token_type
的值。
enum token_type {
TT_ERROR = -1,
TT_EOF = 0,
TT_TAG_START,
TT_TAG_END,
TT_ATTR,
TT_WORD,
TT_SPACE,
TT_DATA,
TT_COMMENT_START, TT_COMMENT_END,
TT_CDATA_START, TT_CDATA_END,
TT_PI_START, TT_PI_END,
TT_ENTITY_START, TT_ENTITY_END,
};