【问题标题】:Can't assign HTML to HTMLDocument.body无法将 HTML 分配给 HTMLDocument.body
【发布时间】:2022-01-15 23:49:46
【问题描述】:

我想使用来自mshtml 库的HTMLDocument 对象。我试图将 HTML 分配给文档:

var doc = new mshtml.HTMLDocument();
var html = File.ReadAllText(@"path_to_html_file");
doc.body.innerHTML = html; // <-- this line throws error

但是,我在第三行得到错误:

System.NullReferenceException: '对象引用未设置为 对象的实例。'
mshtml.DispHTMLDocument.body.get 返回 null。

我尝试使用动态代码,但也没有用:

dynamic doc = Activator.CreateInstance(Type.GetTypeFromProgID("htmlfile"));

在这种情况下,我收到以下错误:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'无法对空引用执行运行时绑定'

有没有办法解决这个问题?谢谢!

更新:VBA 代码

Sub GetData()
    Dim doc As MSHTML.HTMLDocument
    Dim fso As FileSystemObject, txt As TextStream

    Set doc = New MSHTML.HTMLDocument
    Set fso = New FileSystemObject
    Set txt = fso.OpenTextFile("path_to_html_file")
    doc.body.innerHTML = txt.ReadAll() '// <-- No error here
    txt.Close
End Sub

【问题讨论】:

  • 你确定文件的路径有效吗?
  • @preciousbetine 问题不是与文件有关。
  • @preciousbetine 我在 VBA 中使用了相同的代码(已对其进行了调整) - 它运行良好。
  • 您的文档body 属性似乎为空。为什么要尝试创建新文档而不是引用 doc 变量到现有文档?
  • @ymz 是的,我知道问题在于bodynull。问题是 - 为什么它在 VBA 中有效,但在 C# 中无效。

标签: c# .net mshtml


【解决方案1】:

您可以将 mshtml.HtmlDocument 强制转换为 IHTMLDocument2 接口,以使主要对象的属性和方法可用:

var doc = (IHTMLDocument2)new mshtml.HTMLDocument();

或者使用带有类型 Guid 的 Activator.CreateInstance() 创建一个 HtmlDocumentClass 实例,然后转换为 IHTMLDocument2 接口。

IHTMLDocument2 doc = 
   (IHTMLDocument2)Activator.CreateInstance(
       Type.GetTypeFromCLSID(new Guid("25336920-03F9-11CF-8FD0-00AA00686F13")));

这或多或少是一回事。我更喜欢第一个,主要是for this reason

然后,您可以随意写信给HtmlDocument。例如:

doc.write(File.ReadAllText(@"[Some Html Page]"));
Console.WriteLine(doc.body.innerText);

要创建一个 HtmlDocument,一个骨架 HTML 页面就足够了,如下所示:

string html = "<!DOCTYPE html><html><head></head><Body><p></body></html>";
doc.write(html);

注意:在创建 Document 之前,页面中的所有元素都是null

之后,您可以将Body.InnerHtml 设置为其他值:

doc.body.innerHTML = "<P>Some Text</P>";
Console.WriteLine(doc.body.innerText);

请注意,如果您需要更广泛地使用 HTML 文档,则必须转换为更高级别的接口:IHTMLDocument3IHTMLDocument8(截至目前),取决于系统版本。

经典的getElementByIdgetElementsByNamegetElementsByTagName方法在IHTMLDocument3接口中可用。

例如,使用 getElementsByTagName() 来检索 HTMLElementInnerText,使用它的标签名称:

string innerText = 
   (doc as IHTMLDocument3).getElementsByTagName("body")
                          .OfType<IHTMLElement>().First().inne‌​rText;

注意
如果您找不到 IHTMLDocument6IHTMLDocument7IHTMLDocument8 接口(以及可能在 MSDN 文档中引用的其他接口),那么您可能在 \Windows\Assembly\ GAC 中有一个旧的类型库。按照 Hans Passant 的建议创建一个新的 Interop.mshtml 库:
How to get mshtml.IHTMLDocument6 or mshtml.IHTMLDocument7?

【讨论】:

  • 感谢您的回答,但不幸的是 IntelliSense 显示最大版本 IHTMLDocument5 - 此版本既没有 body 属性也没有 getElementById 方法。此外,Activator.CreateInstance 也没有帮助 - 错误表明 body 为空。
  • 转换为IHtmlDocument2,如示例所示。其他接口提供不同的方法和属性。请参阅文档了解每个接口可用的内容。
  • 虽然IHtmlDocument2支持body,但是又为null了。而且,它不支持getElementById! :)
  • 我想,我需要坚持使用 VBA 或使用 HtmlAgilityPack :)
  • 您使用的是什么系统和框架/mshtml 版本?。这是一个非常经典的设置。 + 在设置任何东西之前,你有没有 .write 给文档?你的代码中有using mshtml;吗?
【解决方案2】:

我也遇到了 System.NullReferenceException,因为 doc.body 为空。最后,我是这样解决问题的:

   public void SetWebBrowserHtml(WebBrowser webBrowser, string html)
    {
        if (!(webBrowser.Document is MSHTML.IHTMLDocument2))
        {
            webBrowser.Navigate("about:blank");
        }
        if (webBrowser.Document is MSHTML.IHTMLDocument2 doc)
        {
            if (doc.body == null)
            {
                doc.write(html);
            }
            else
            {
                doc.body.innerHTML = html;
            }
        }
    }

【讨论】:

    猜你喜欢
    • 2015-06-19
    • 2020-03-31
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 2021-06-21
    相关资源
    最近更新 更多