接下来的两篇我将介绍怎样从DOM流中解析出组成网页的最基本的两种元素:文字和图像。
上一篇我说过网页是由许多嵌套的frame组成,而每一个frame都是一个独立的单元,他们包含自己的文字和图片。解析文字和图片有以下两种情况:
1. 他们都直接放置在网页“BODY”层,此时我不用考虑这些frame导致的布局影响。这是最简单的一种情形。
2. 而常见的情形是他们被放置于嵌套的frame中,比如Button控件上的文字,TextBox控件中的文字等。
l 文字
1. “BODY“层的文字
文字在DOM语言中有好多种标签可以代表他,比如Label,Title,和Anchor等等。他们都表示有文字。
· 首先,我需要得到文字的位置以及他的本体文字,这可一从IHTMLElement接口中获得。
IHTMLElement Members(从MSDN摘录的片段)
offsetParent |
Retrieves a reference to the container object that defines the IHTMLElement::offsetTop and IHTMLElement::offsetLeft properties of the object. |
offsetHeight |
Retrieves the height of the object relative to the layout or coordinate parent, as specified by the IHTMLElement::offsetParent property. |
offsetLeft |
Retrieves the calculated left position of the object relative to the layout or coordinate parent, as specified by the IHTMLElement::offsetParent property. |
offsetParent |
Retrieves a reference to the container object that defines the IHTMLElement::offsetTop and IHTMLElement::offsetLeft properties of the object. |
offsetTop |
Retrieves the calculated top position of the object relative to the layout or coordinate parent, as specified by the IHTMLElement::offsetParent property. |
offsetWidth |
Retrieves the width of the object relative to the layout or coordinate parent, as specified by the IHTMLElement::offsetParent property. |
innerText |
Sets or retrieves the text between the start and end tags of the object. |
下面是可行的伪代码:
long ltop, lleft, lHeight, lwidth;
hr = spElement->get_offsetLeft(&lleft);
hr = spElement->get_offsetTop(<op);
hr = spElement->get_offsetHeight(&lHeight);
hr = spElement->get_offsetWidth(&lwidth);
BSTR bstrInnerText;
hr = spElement->get_innerText(&bstrInnerText);
· 关于文字的字体风格,如字体大小,字体族,是否加粗,倾斜等等,我就只能从CSS流中解析。而CSS流的代表接口就是IHTMLCurrentStyle。
IHTMLCurrentStyle Members(从MSDN摘录的片段)
fontFamily |
Sets or retrieves the name of the font used for text in the object. |
fontSize |
Sets or retrieves a value that indicates the font size used for text in the object. |
fontStyle |
Sets or retrieves the font style of the object as italic, normal, or oblique. |
fontVariant |
Sets or retrieves whether the text of the object is in small capital letters. |
fontWeight |
Sets or retrieves the weight of the font of the object. |
下面是可行伪代码:
CComQIPtr<IHTMLElement> spElement;
CComQIPtr<IHTMLElement2> spElement2(spElement);
CComQIPtr<IHTMLCurrentStyle>spCurrentStyle;
spElement2->get_currentStyle(&spCurrentStyle);
VARIANT varfontSize;
varfontSize.vt = VT_BSTR;
spCurrentStyle->get_fontSize(&varfontSize);
VARIANT varfontWeight;
varfontWeight.vt = VT_BSTR;
spCurrentStyle->get_fontWeight(&varfontWeight);
VARIANT varHeight;
varHeight.vt = VT_BSTR
spCurrentStyle->get_height(&varHeight);
这里你所取得的fontFamily的值是一个字体族列表,其中的每个字体族用分号隔开以防止当有多种字体族混杂在一起。此值主要由两部分组成:字体族名称和通用字体族名称。如果字体族名称包含空白符,它应该出现一个或两个引号;通用字体族名称不用包含在引号中。
为什么要这样组织字体族名称呢?这主要是因为你不知道客户端安装了什么字体, 你应该提供用户一个备用的字体族 – 通用字体族名称在字体族名称列表的末尾,防止如果客户端没有安装字体族名称指定的字体时,可以用通用字体族名称来替代。
这个字体族名称列表也可以包含嵌入字体。此外,关于fontFamily的默认值可以通过Microsoft Internet Explorer->Internet Options menu->General tab->Fonts button来设置。
综上所述,IE浏览器是这样来应用字体的:首先他会从DOM中解析出fontFamily的字体列表,然后他会尝试其中的每一个字体,直到找到一种客户端已经安装的字体族。如果到列表末尾,IE浏览器依然没有找到相应的字体,那么他就会使用IE设置的那个默认字体。
此外,在上面的伪代码中所得到的字体大小,高度,宽度等数据,他们返回的值有可能不是绝对的数值,如8pt。相反,它可能是一种相对值(相对上一层字体),比如:xx-small,x-small,larger,smaller等等。这不可避免地要求我们自己将这些抽象概念转化为绝对数值。特别是,如果给出的是百分比,我们可能需要递归算出这些数值。
最糟糕的是,有时候你可能取得的是负值,比如:“-1”,“-2”。这意味着字体大小必须转化为设备单位,而且匹配它的绝对数值通过可用字体字符的高度。
· 文字颜色是个很麻烦的问题,可以用下面的代码:
CComQIPtr<IHTMLCurrentStyle>spCurrentStyle;
VARIANT varColor;
varColor.vt = VT_BSTR|VT_I4;
spCurrentStyle->get_color(&varColor);
但是请注意返回的varColor是一个BSTR值,而且是专属于网页设计的一组颜色值,如果你想使用RGB颜色值,必须自己进行转换。而且,DOM常常会简写这个颜色值,比如#00ccff,从上面的代码取出来的值可能是#0cf。
· 文字编码问题
我们可以在IE浏览器中设置网页的编码,这些信息我们也可以从DOM中获取.
BSTR bstrCharset;
spHTMLDocument2->get_charset(&bstrCharset);
2. 嵌套容器中的文字
我打算以Table控件中的文字为例,其他控件容器中的文字可以按类似的方法来处理
· Get text in Table
许多网页中都有Table控件,每个Table都有自己的文字。比如,下面这个Table:
|
· 文字分行
网页中的文字是没有分行符让你判断文字该到哪个字分行,这是一个大麻烦,尤其对于那些做文件格式转化的程序员而言。因为这意味着虽然你可以得到上面的那一大段文字,但是,你不知道怎么来断行。唯一可行的办法就是自己设计算法来分行,但只是一件非常复杂的事。
你想一想,你既要考虑字体目前的大小,还要调整Table一行是多宽,从而计算每一行最多可以放几个字。其中,还要加上字跟字,行跟行之间的间距值。这实在是个很烦琐的事。
· Table中文字的位置
现在文字的位置需要考虑连个因素:一个是文字相对于Table的位置;另一个是整个Table相对于网页的位置。
IHTMLTable Members(从MSDN摘录)
align |
Sets or retrieves a value that indicates the table alignment. |
cellPadding |
Sets or retrieves the amount of space between the border of the cell and the content of the cell. |
cellSpacing |
Sets or retrieves the amount of space between cells in a table. |
height |
Sets or retrieves the height of the object. |
width |
Sets or retrieves the width of the object. |
IHTMLTableCell Members(从MSDN摘录)
colSpan |
Sets or retrieves the number columns in the table that the object should span. |
height |
Sets or retrieves the height of the object. |
noWrap |
Sets or retrieves whether the browser automatically performs wordwrap. |
rowSpan |
Sets or retrieves how many rows in a table the cell should span. |
vAlign |
Sets or retrieves how text and other content are vertically aligned within the object that contains them. |
width |
Sets or retrieves the width of the object. |
关于这一点我会在后面详细讨论,这也是一个浩大的解析过程。