从HTML节点中读取值

5

我是新手,对XML/HTML解析一无所知。甚至不知道如何用正确的术语搜索重复项。

我有一个HTML文件,它看起来像这样:

<body id="s1" style="s1">
    <div xml:lang="uk">
        <p begin="00:00:00" end="00:00:29">
          <span fontFamily="SchoolHouse Cursive B" fontSize="18">I'm great!</span>
        </p>

现在我需要从中获取00:00:0000:00:29I'm great!。可以这样阅读:
XmlTextReader reader = new XmlTextReader(file);
while (reader.Read())
{
    if (reader.NodeType != XmlNodeType.Element)
        continue;

    if (reader.LocalName != "p")
        continue;

    var a = reader.GetAttribute(0);
    var b = reader.GetAttribute(1);

    if (reader.LocalName == "span")
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(reader);
        XmlNode elem = doc.DocumentElement.FirstChild;
        var c = elem.InnerText;
    }
 }

我将变量 abc 中的值提取出来。但是 HTML 格式稍有改变。现在 HTML 的格式如下:

<body id="s1" style="s1">
  <div xml:lang="uk">
      <p begin="00:00:00" end="00:00:29">I'm great! </p>

在这种情况下,我该如何解析出 00:00:0000:00:29I'm great!?我尝试了以下代码:
XmlTextReader reader = new XmlTextReader(file);
while (reader.Read())
{
    if (reader.NodeType != XmlNodeType.Element)
        continue;

    if (reader.LocalName != "p")
        continue;

    var a = reader.GetAttribute(0);
    var b = reader.GetAttribute(1);

    XmlDocument doc = new XmlDocument();
    doc.Load(reader);
    XmlNode elem = doc.DocumentElement.FirstChild;
    var c = elem.InnerText;
}

但是我遇到了这个错误:该文档已经有了一个'DocumentElement'节点。doc.Load(reader)的代码行上。如何正确读取并导致问题的原因是什么?我正在使用.NET 2.0


2
看一下 html agility pack,似乎是你需要解析 HTML 的工具。 - oleksii
@oleksii 当 System.Xml 下有大量库可供使用时,我是否真的需要使用第三方库?而且我也没有做任何与 HTML 相关的事情。 - nawfal
很明显XML!= HTML,我认为如果您需要进行任何HTML解析,则HTML敏捷包将非常有用,因为样本中似乎有一些HTML。如果您不使用HTML,则可以尝试使用LINQ-to-XML。 - oleksii
@oleksii:我的意思是针对那个操作员,不是针对你 :) 我基本上只是确认你说的话。 - Philip Daubmeier
有人能相应地编辑一下问题的标题吗?我不太确定这个XML听起来像HTML的时候。 - nawfal
2个回答

6
看起来您有一些HTML需要使用XML解析器进行解析。这也可能是您出现“此文档已经具有'DocumentElement'节点”的异常的原因:因为您有多个根节点,在HTML中允许(或更好:容忍),但在XML中不允许。
使用HTML解析器代替。不幸的是,.NET框架内没有内置解析器。您必须选择第三方库进行解析。其中一个非常好的库是oleksii在他的评论中提到的HTML Agility Pack
从您的评论中,我感到您不熟悉HTML和XML之间没有直接关系这一事实。从这里获取的图表很好地说明了这一点:
SGML、HTML和XML之间的关系 既不是XML的子集,也不是HTML的子集。只有当您使用严格的XHTML(很少见)时,您才有一个可以使用XML解析器解析的HTML文档。但是请注意,如果XHTML文档的代码有错误,解析器将失败,而常见浏览器将继续显示页面。此外,随着HTML5缓慢而稳步地到来,XHTML的未来变得非常不确定...
总之:为避免所有这些陷阱,请选择易于使用的HTML解析器。

使用.NET XML类无法解析的内容吗? - nawfal
不幸的是,HTML不是XML的子集。此外,由于HTML解析器(包括浏览器中使用的解析器)在解析无效输入方面要宽容得多,人们开始为网站编写无效的HTML,或者根本不关心有效性。但是,XML解析器期望严格有效的*输入,如果不是这样,它们会停止解析并抛出异常,就像您看到的那样。 - Philip Daubmeier
你能相应地编辑问题的标题吗?我不太确定这个XML听起来像HTML的时候。 - nawfal
@nawfal:我编辑了你的问题标题并纠正了标签。 - Philip Daubmeier

3

如果您想解析HTML,可以使用WebClient(或WebBrowser)加载页面,然后使用HTML DOM来浏览它。您需要为以下代码示例添加对Microsoft HTML Object Library(COM)的引用:

  string html;
  WebClient webClient = new WebClient();
  using (Stream stream = webClient.OpenRead(new Uri("http://www.google.com")))
  using (StreamReader reader = new StreamReader(stream))
  {
    html = reader.ReadToEnd();
  }
  IHTMLDocument2 doc = (IHTMLDocument2)new HTMLDocument();
  doc.write(html);
  foreach (IHTMLElement el in doc.all)
    Console.WriteLine(el.tagName);

我之前尝试将HTML加载到XML中,但是太过复杂 - 需要修复未关闭的标签(例如<BR>),给属性加上引号,为没有值的属性赋值等等。因为我想要使用XSLT对其进行处理,所以我将其加载到HTML DOM中并遍历其中的节点,为每个HTML节点创建相应的XML节点,这样我就得到了一个合适的HTML的XML表示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接