【问题标题】:Iterate through an html string to find all img tags and replace the src attribute values遍历一个 html 字符串以查找所有 img 标签并替换 src 属性值
【发布时间】:2016-09-30 07:04:05
【问题描述】:

我有一个 html 代码作为字符串。我需要找到该字符串中的所有 img 标签,读取每个 src 属性的值并将其传递给一个函数,该函数返回一个完整的 img 标签,该标签需要代替所读取的 img 标签。

它需要遍历整个字符串并对所有img标签执行相同的逻辑。

例如,假设我的 html 字符串如下所示:

string htmlBody= "<p>Hi everyone</p><img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA..." <p>I am here </p> <img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAC..." />"

我有以下代码找到第一个 img 标签,获取 src 值(这是一个 base64 字符串)并将其转换为位数组以创建一个流,然后我可以创建一个新的 src 值链接到那个流。

  //Remove from all src attributes "data:image/png;base64"      
  string res = Regex.Replace(htmlBody, "data:image\\/\\w+\\;base64\\,", "");
  //Match the img tag and get the base64  string value
  string matchString = Regex.Match(res, "<img.+?src=[\"'](.+?)[\"'].*?>", RegexOptions.IgnoreCase).Groups[1].Value;
  var imageData = Convert.FromBase64String(matchString);
  var contentId = Guid.NewGuid().ToString();
  LinkedResource inline = new LinkedResource(new MemoryStream(imageData), "image/jpeg");
  inline.ContentId = contentId;
  inline.TransferEncoding = TransferEncoding.Base64;
  //Replace all img tags with the new img tag 
  htmlBody = Regex.Replace(htmlBody, "<img.+?src=[\"'](.+?)[\"'].*?>", @"<img src='cid:" + inline.ContentId + @"'/>");

正如你所看到的,我已经得到了新的 img 标签来替换:

   <img src='cid:" + inline.ContentId + @"'/>

但是代码会将所有img标签替换为相同的内容。我需要能够获取 img 标签,执行逻辑,替换它,然后继续下一个 img 标签。

希望你能给我一个想法,我该怎么做。提前致谢。

【问题讨论】:

    标签: c# regex string image


    【解决方案1】:

    如果我正确理解您的需求,您可以为此目的使用 HtmlAgilityPack。使用正则表达式可能会导致不需要的行为。你可以试试下面的代码吗?

    public static string DoIt()
    {
            string htmlString = "";
            using (WebClient client = new WebClient())
                htmlString = client.DownloadString("http://dean.edwards.name/my/base64-ie.html"); //This is an example source for base64 img src, you can change this directly to your source.
    
            HtmlDocument document = new HtmlDocument();
            document.LoadHtml(htmlString);
            document.DocumentNode.Descendants("img")
                                .Where(e =>
                                {
                                    string src = e.GetAttributeValue("src", null) ?? "";
                                    return !string.IsNullOrEmpty(src) && src.StartsWith("data:image");
                                })
                                .ToList()
                                .ForEach(x =>
                                {
                                    string currentSrcValue = x.GetAttributeValue("src", null);
                                    currentSrcValue = currentSrcValue.Split(',')[1];//Base64 part of string
                                    byte[] imageData = Convert.FromBase64String(currentSrcValue);
                                    string contentId = Guid.NewGuid().ToString();
                                    LinkedResource inline = new LinkedResource(new MemoryStream(imageData), "image/jpeg");
                                    inline.ContentId = contentId;
                                    inline.TransferEncoding = TransferEncoding.Base64;
    
                                    x.SetAttributeValue("src", "cid:" + inline.ContentId);
                                });
    
    
            string result = document.DocumentNode.OuterHtml;
    }
    

    您可以从 https://www.nuget.org/packages/HtmlAgilityPack 检索 HtmlAgilityPack

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      我认为您需要为从字符串中提取的每个 img 迭代您的代码。 以下代码为您提供了所有 img 标签的列表:

      public static List<string> FetchImgsFromSource(string htmlSource)
              {
                  List<string> listOfImgdata = new List<string>();
                  string regexImgSrc = @"<img[^>]*?src\s*=\s*[""']?([^'"" >]+?)[ '""][^>]*?>";
                  MatchCollection matchesImgSrc = Regex.Matches(htmlSource, regexImgSrc, RegexOptions.IgnoreCase | RegexOptions.Singleline);
                  foreach (Match m in matchesImgSrc)
                  {
                      string href = m.Groups[1].Value;
                      listOfImgdata.Add(href);
                  }
                  return listOfImgdata;
              }
      

      循环使用这个列表和用户逻辑:

      foreach (var item in listOfImgdata )
                  {
                      var imageData = Convert.FromBase64String(item);
                      var contentId = Guid.NewGuid().ToString();
                      LinkedResource inline = new LinkedResource(new MemoryStream(imageData), "image/jpeg");
                      inline.ContentId = contentId;
                      inline.TransferEncoding = TransferEncoding.Base64;
                      //Replace all img tags with the new img tag 
                      htmlBody = Regex.Replace(htmlBody, "<img.+?src=[\"'](.+?)[\"'].*?>", @"<img src='cid:" + inline.ContentId + @"'/>");
                  }
      

      希望它对你有用。

      另外,解析 HTML dom 的最佳方法是使用其他人提到的 HtmlAgilityPack。

      【讨论】:

      • 感谢@Pramodab。这是一个很好的方法。唯一的问题是最后一行代码用最新的 html img 标签替换了所有图像。也许它可以改进,但是“Cihan”答案与 HtmlAgilityPack 配合得很好。
      • 这对我的 xamarin 项目帮助很大,非常感谢 =)
      猜你喜欢
      • 1970-01-01
      • 2011-02-07
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 2015-09-19
      相关资源
      最近更新 更多