【问题标题】:Get an element from a large html file从一个大的 html 文件中获取一个元素
【发布时间】:2016-10-07 22:58:43
【问题描述】:

我有一个大的 html 文件(80 个月),例如:

<html>
   <head>...</head>
   <body>
      <div class="nothing">...</div>
      <div class="content">
         <h1>Hello</h1>
         <div>
            <div class="phone"> ... </div>
            <div class="phone"> ... </div>
            <div class="phone"> ... </div>
         </div>
         <div>
            <div class="phone">
               ...
               <div>
                  ...
               </div>
               ...
            </div>
            <div class="phone"> ... </div>
         </div>
         <div>
            <div class="phone"> ... </div>
            <div class="phone"> ... </div>
            <div class="phone"> ... </div>
            <div class="phone"> ... </div>
         </div>
      </div>
   </body>
</html>

我无法手动修改这个 html 文件,所以最好是保持只读状态。

我想将&lt;div class="phone"&gt; ... &lt;/div&gt; 的每一行存储在一个字符串表中,以便以后能够对其进行操作。在那个 div 里面,还有其他元素可以是任何东西。

  1. 我尝试使用 HtmlDocument 和 XmlDocument 来加载此文件,但文件太大,导致出现内存不足异常
  2. 我尝试使用 Regex 来获取表格中的所有这些元素,但我无法管理它。

我使用的正则表达式是:

Regex.Matches(myHtml, "<div class=\"phone\">[\\p{L}\\s]*\\,*[\\p{L}\\s]*<div");

这个正则表达式需要每个

<div class="phone"> ANY UTF8 char </div>

但问题是:这个正则表达式获取所有 UTF8 字符,直到找到下一个 &lt;/div&gt; 但这个关闭 div 不一定是第一个打开 div 的关闭 div。

有什么想法可以做到这一点吗?我们不能把这个文件剪成不同的字符串以便能够将它加载到 htmlDocument 中吗?

谢谢。

【问题讨论】:

  • 您是否尝试过使用仅转发的XmlReaderXPathNavigator 方法?
  • XPathNavigator 得到我的投票;它应该具有最低的内存占用,因为您正在查询文件而不是将整个内容加载到内存中。
  • 我遇到了 XPathNavigator 的问题。像“十六进制值 0x0C,是无效字符”之类的东西。要解决它,它需要使用 Regex.Replace... 但我得到了内存不足异常... (stackoverflow.com/questions/21053138/…) 所以,我使用了 XmlReader 并且它正在工作:) 谢谢!

标签: c# html asp.net regex


【解决方案1】:

您可以使用XmlReader 类来读取文件。 XmlReader不会将整个文件加载到内存中,但允许您在动态解析文档时逐个节点地移动 XML 文档。

关于如何读取所有 class= phone 的 div 内容的示例:

using (XmlReader reader = XmlReader.Create(@"C:\A.html"))
{
     // Loop over all xml tags 
     while (reader.Read())
     {
          // Check we have a div whith attribute class = phone
          if(reader.Name == "div" && reader.GetAttribute("class") == "phone")
          {
               // Yes, so read until the corresponding closing tag and output content
               textBox1.AppendText(reader.ReadInnerXml() + Environment.NewLine);
          }
     }
}

更多详情请参阅documentation

【讨论】:

  • 这段代码的问题在于ReadInnerXml() 与Read() 具有相同的功能。两者都移动到下一个标签。例如,ReadInnerXml 发生,指针将继续下一个
    然后当我们到达条件 while 时,它​​再次跳转到下一个标签......所以它错过了 1 个标签......
  • 如果您不介意,我编辑了您的代码。感谢您的帮助。
  • 仍需改进
  • 其实ReadInnerXml相当于调用Read。 ReadInnerXml 读取直到结束标记并将阅读器的指针更改为下一个标记。在第一个循环之后, reader.Read() 的执行再次将阅读器的指针更改为下一个标签。因此,同时跳过了一个标签。
    ...
    跳过这个 div
    ...
  • 这不是真的。 ReadInnerXml 指向当前标签的末尾。那是真实的。但是只有对 Read 的调用才会使下一个标签成为当前标签。所以当前代码版本不会丢失任何标签。
【解决方案2】:

您可以使用 jQuery 循环使用类 phone 的所有元素,并将它们存储在 HiddenField 中。然后在 PostBack 上,您可以访问这些值并对其进行处理。

<asp:HiddenField ID="HiddenField1" runat="server" />

<script type="text/javascript">
    function getValues() {
        var valueArray = new Array();
        var valueString = "";
        $(".phone").each(function (index, element) {
            //for demo store both in hiddenfield and javascript array
            valueArray.push(element.innerHTML);
            valueString += element.innerHTML + ",";
        });
        $("#<%=HiddenField1.ClientID %>").val(valueString);
    }
</script>

在代码隐藏中:

    protected void Button1_Click(object sender, EventArgs e)
    {
        string valueString = HiddenField1.Value;
        if (!string.IsNullOrEmpty(valueString))
        {
            string [] valueArray = valueString.TrimEnd(',').Split(',');
            foreach (string s in valueArray)
            {
                //do stuff
            }
        }
    }

【讨论】:

    猜你喜欢
    相关资源
    最近更新 更多
    热门标签