WebBrowser.DocumentText的设置问题

1、最初的愿望
WebBrowser是一个操作Html的极为方便的类。笔者在试图获取一段HTML的标签时,毫不犹豫地瞄上了这个类。

HTML片断:
<HTML>
    <BODY>
        <DIV name="Span1">Simple HTML</DIV>
        <table>
     <tr>
  <td>Input content</td>
  </td>
    </tr>
 </table>
    </BODY>
</HTML>

笔者打算,通过一个Winform程序,获得这段html里的<table><tr><td>等标签。


2、遭遇挫折

为了获取那些标签,笔者写了如下这段代码:

为便于阅读,先定义两个变量:
string htmlCode = ""; //用于存放HTML源码
string outputTags = ""; //用于存放获取的标签


htmlCode = @"<HTML>
    <BODY>
        <DIV name="Span1">Simple HTML</DIV>
        <table>
     <tr>
  <td>Input content</td>
    </tr>
 </table>
    </BODY>
</HTML>"

WebBrowser wbrws = new WebBrowser();
wbrws.DocumentText = htmlCode;

StringBuilder st = new StringBuilder();//用于存储标签

//WebBrowser.Document.All属性表示HTML文档的所有标签
foreach (HtmlElement he in wbrws.Document.All)
{
   st.Append("<");
   st.Append(he.TagName);
   st.Append(">");
}

outputTags = st.ToString();

 

想象中,outputTags应该输出标签,但事与愿违,outputTags中什么也没有。通过调试,发现wbrws.Document.All.Count的值为0,换句话说,获得的标签数为0。

通过进一步观察,在调试过程中发现:无论HTML源码如何变,wbrws.DocumentText的值永远都是"<HTML></HTML>/0"语句wbrws.DocumentText = htmlCode;将HTML源码赋与了wbrws的DocumentText属性啊,为什么没有了呢?

 

3、曙光出现
要解决这个问题,笔者试图在百度、Google上一翻折腾,希望碰到解决过这个问题的前辈(吸取前人经验,是提高效率的表现嘛,不算偷懒)。百度让我失望,Google也同礼相待。无奈,只得再返MSDN,细细阅读WebBrowser.DocumentText 属性的内容。

这段内容的相关事项解释集中在备注里:
[[
如果要使用字符串处理工具操作显示在 WebBrowser 控件中的 HTML 页的内容,则使用该属性。例如,可以使用该属性从数据库加载页,也可以使用正则表达式分析页。设置该属性时,WebBrowser 控件在加载指定文本之前,自动导航到about:blank URL。这意味着设置该属性时,发生 Navigating、Navigated 和 DocumentCompleted 事件,且 Url 属性的值不再有意义。

注意: 
即使已请求了另一个文档,该属性也包含当前文档的文本。如果设置该属性的值,然后立即再次检索该值,那么在WebBrowser 控件尚未来得及加载新内容的情况下,检索到的值可能与设置的值不同。可以检索 DocumentCompleted 事件处理程序中的新值。
 

若要将网页的内容作为 Stream 访问,请使用 DocumentStream 属性。也可以通过 Document 属性,使用 HTML 文档对象模型 (DOM) 访问页内容。

]]

这一段文字表面看起来与我的问题没有关系,但细细一想,设置了DocumentText属性不就是让WebBrowser加载文本吗?那么它必然与会产生Navigating、Navigated、DocumentCompleted事件。换句话说,给DocumentText进行了赋值并不等于它的值

就立即变成了新值,而应该有一个加载的过程,直到加载完成之后其属性值才会是新值。这样的话,要查询DocumentText属

性,就应当在文档加载完成之后,也就是DocumentCompleted事件之后才能获得新值。

 

4、程序改进
为了要实现DocumentCompleted这个事件处理过程,原来的问题,变成了3个过程:

a,添加DocumentCompleted事件;
b,定义DocumentCompleted事件处理函数,使其能够查询DocumentText属性;
c,给DocumentText属性赋新值。

 

程序片段如下:

//定义变量
string htmlCode = ""; //用于存放HTML源码
string outputTags = ""; //用于存放获取的标签
htmlCode = @"<HTML>
  <BODY>
        <DIV name="Span1">Simple HTML</DIV>
        <table>
     <tr>
  <td>Input content</td>
    </tr>
 </table>
    </BODY>
</HTML>"
WebBrowser wbrws = null;

//在窗体加载时添加DocumentCompleted事件
private void Form1_Load(object sender, EventArgs e)
{
   wbrws = new WebBrowser();
   wbrws.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(getTag);
}

//定义DocumentCompleted事件处理函数
private void getTag(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    StringBuilder st = new StringBuilder();
    foreach (HtmlElement he in wbrws.Document.All)
    {
        st.Append("<");
        st.Append(he.TagName);
        st.Append(">/n");
     }

    outputTags = st.ToString(); //输出标签
}

//给DocumentText属性赋值的过程在一个按钮点击事件中进行
private void btnGetTags_Click(object sender, EventArgs e)
{
     wbrws.DocumentText = htmlCode;
}

程序运行的结果,outputTags = "<HTML><HEAD><TITLE><BODY><DIV><TABLE><TBODY><TR><TD>"。
由此可见,程序获得了html标签,如果再进行遍历,就可以分别得到每个标签。

 

5、延伸的思考
a,为什么需要使用DocumentCompleted事件呢?
笔者认为,通常情况下,对于变量赋值可以收到立午见影的效果,但对于属性的赋值,会引起相关的一系列事件,从而对赋值之后的结果产生影响。在对DocumentText属性进行赋值时,HTML源码可能来自于网络,加载的时间可能会比较长,还没加载完成就查询属性值,必然不能得到正确的结果。引入ocumentCompleted事件,就能够保证对属性值的查询结果是正确的值。
b,如果HTML源码的标签不配对时,会得到什么样的结果?如果HTML源码并不完整,没有<html>、<body>等标签,结果又会怎样呢?这个问题,留给读者试验。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值