高级排版之HTML,CSS解析
前言
****关于HTML的解析是在java层,并且只对文本的内容进行提取,具体的排版是由Typeset出处理,渲染是由TextDraw处理.现今提出的高级排版的需求,这种方式就不满足了,HTML中对于文本的样式的定义,也需要进行解析,即对CSS的解析.并且解析引擎在C++层时间,通过JNI的方式调用.
一、HTML解析
HTML是可以解析成一个DOM树形,这里定义了其节点的父子关系,并且定义了其层级,以及标签名称,内容的开始和结尾;
class Node{
private:
long mStart;
long mLength;
string mStrHTML;
string mNodeName;
int mLevel;
bool isAttributeParsed;
TAG mTag;
map<string, string> mAttributes;
vector<Node *> mSubNodes;
Node *mPParentNode;
}
其解析算法就是按照HTML文件流式解析,然后依据当前字符进行不同规则匹配:例如标签的开始字符为’<’,然后遍历字符串,找出标签的名称,属性,以及标签的结束,如果是有子节点,依然重复这个解析算法.这里特别要提到的是如果是以下节点,该节点的内容就要全部作为文本不需要解析.例如:”xmp”,” plaintext”, ”textarea”, ”pre”.
解析的结果最主要的就是要产生Node的Dom树型数据.这个是由addNode这个方法来保证,示例如下:
Node *HTML::addNode(stack<Node *> &nodeStack, bool isPush2Stack){
Node *node=new Node();
if(nodeStack.empty()){
mNodes.push_back(node);//添加到根节点队列中
node->setLevel(0);
}else{
Node *parentNode=nodeStack.top();
parentNode->addSubNode(*node);//当作上一节点的子节点
node->setLevel(parentNode->getLevel()+1);
}
if(isPush2Stack){
nodeStack.push(node);//当前Node压如栈中
}
return node;
}
其HTML文本的内容是有text()方法来获得.text()方法就是要遍历HTML的解析结果vector<Node *>.示例如下:
string HTML::text(){
string strText;
if(!mNodes.empty()){
vector<Node *>::iterator iEnd=mNodes.end();
for(vector<Node *>::iterator it=mNodes.begin(); it<iEnd; it++){
extraction(*it, strText);
}
}
return strText;
}
void HTML::extraction(Node * n, string &content){
if(n->getTag()==_tag){
if(n->hasSubNodes()){
vector<Node *> nvs=n->getSubNodes();
vector<Node *>::iterator ivE=nvs.end();
for(vector<Node *>::iterator i=nvs.begin(); i<ivE; i++){
extraction(*i, content);
}
}else{
n->append(content);
}
}else if(n->getTag()==_text || n->getTag()==_intact_text){
n->append(content);
}
}
二、CSS解析
HTML解析完成之后,就可以通过StyleSheet *HTML::getStyleSheet();方法来获取CSS对象. getStyleSheet()分析HTML中关于<link>部分的内容.最后解析的结果数据结构如下:
//子串
struct SubAttr{
string key;
string value;
MATCH mat;
};
//选择器
struct Selector{
string elem;
vector<struct SubAttr *> attrs;
SLT flag;
string pseudo;
Selector *super;
};
//声明
struct Declaration{
string prop;
string val;
int weight;
int count;
};
//css rule
struct Rule{
struct Selector *slt;
vector<struct Declaration *> decles;
int weight;
bool isLayer;
};
CSS的解析也还是文本流式解析,从中获取CSS的选择器,申明等,通过addRule方法将生成CSS样式集合.
void StyleSheet::addRule(vector<Rule *> &tempVct, string selName, SLT flag){
if(!selName.empty()){
#ifdef __DEBUG_
Utils::Log("$$ "+selName+": ");
#endif
struct Rule *pRule;
pRule=NULL;
vector<Rule *>::iterator itEnd=mRules.end();
for(vector<Rule *>::iterator it=mRules.begin(); it<itEnd; it++){
if((*it)->slt->flag==flag && (*it)->slt->elem==selName){
pRule=*it;
break;
}
}
if(pRule==NULL){
pRule=new Rule();
pRule->slt->elem=selName;
pRule->slt->flag=flag;
mRules.push_back(pRule);//添加到解析结果队列
}
tempVct.push_back(pRule);//添加到缓存队列
}
}