遍历HTML字符串以查找所有img标签并替换src属性值。

9

我有一个作为字符串的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标签。

希望您能给我一个想法,如何做到这一点。谢谢提前。

2个回答

21

如果我正确理解您的需求,您可以使用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。

希望这能帮到您。


9

我认为你需要对从字符串中获取的每个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中非常有效。 - D.B
1
这对我的Xamarin项目非常有帮助,非常感谢 =) - Eman
这个功能非常好用,但它正在用最终的图像标签替换图像,你能提供解决方案吗? - Nimesh khatri

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