【问题标题】:How do I hide images that have a certain class when creating a pdf from html?从 html 创建 pdf 时,如何隐藏具有特定类别的图像?
【发布时间】:2016-02-05 05:15:17
【问题描述】:

我在使用 iTextSharp (5.x) 将 html 转换为 pdf 时尝试隐藏包含特定类的图像元素时遇到问题。

我无法访问原始 Html,因为它来自其他来源,但是,我可以在获得它后在 C# 中执行 Regex 和 string.replace 等基本操作。

Html 字符串的一个简单示例如下所示:

<div>
    <div>
        <img src="somepath/desktop.jpg" class="img-desktop">Desktop</img>
        <img src="somepath/mobile.jpg" class="img-mobile">Mobile</img>
    </div>
</div>

然后使用 iTextSharp 中的 XMLWorker 将这个字符串创建为 PDF。

我需要隐藏第二张图片,更一般地说,任何带有“img-mobile”类的图片元素。

我尝试过的:

  • 将 img.img-mobile {display:none} 添加到创建 pdf 时发送的 CSS 中
  • 将 img.img-mobile {width:0;height:0} 添加到 CSS 中
  • 将 @media print { img.img-mobile: display:none} 添加到 CSS 中
  • 在 CSS 中添加 @media print { img.img-mobile: width:0;height:0}
  • 使用正则表达式查找具有该类的 img 元素,然后遍历匹配项,将源替换为空源并将该字符串的原始 html 替换为新字符串(不幸的是,我的正则表达式没有抓取任何匹配项)

            var pattern = "<img.*?class=\"img-mobile.*\"\\s?>.*</img>";
            var mobileImages = Regex.Matches(innerHtml, pattern);
            var srcPattern = "src=\".*\" ";
            foreach (var imageElement in mobileImages)
            {
    
                var replaceString = Regex.Replace(imageElement.ToString(), srcPattern, " ");
                innerHtml.Replace(imageElement.ToString(), replaceString);
            }
    

我很快就没有关于如何处理这个问题的想法了……唯一的优点是进来的 Html 是一致的,因为工具正在其他地方生成它。因此,当用户“将图像添加到该 html”时,它的结构总是相同的,因此 Regex 和 replace 方法是可以接受的,尽管 CSS 方法会更受欢迎......

【问题讨论】:

    标签: c# html css regex itextsharp


    【解决方案1】:

    即使您是Regex 专家并且如上所述您的输入是可预测的,解析 HTML 也很困难。更好和更简单的方法是使用经过测试/验证的解析器,几乎所有编程语言都可以使用该解析器。对于 .NET,它是 HtmlAgilityPack。如果您知道一点XPath,它与 CSS 选择器非常相似,那么设置和选择要删除的特定节点非常简单:

    string RemoveImage(string htmlToParse)
    {
        var hDocument = new HtmlDocument()
        {
            OptionWriteEmptyNodes = true,
            OptionAutoCloseOnEnd = true
        };
        hDocument.LoadHtml(htmlToParse);
        var root = hDocument.DocumentNode;
        var imagesDesktop = root.SelectNodes("//img[@class='img-desktop']"); 
        foreach (var image in imagesDesktop)
        {
            var imageText = image.NextSibling;
            imageText.Remove();
            image.Remove();
        }
        return root.WriteTo();
    }
    

    然后将解析后的 H​​TML 传递给 iTextSharp:

    var parsedHtml = RemoveImage(HTML);
    using (var xmlSnippet = new StringReader(parsedHtml))
    {
        using (FileStream stream = new FileStream(
            outputFile,
            FileMode.Create,
            FileAccess.Write))
        {
            using (var document = new Document())
            {
                PdfWriter writer = PdfWriter.GetInstance(
                    document, stream
                );
                document.Open();
                XMLWorkerHelper.GetInstance().ParseXHtml(
                    writer, document, xmlSnippet
                );
            }
        }
    }
    

    使用您提供的 HTML sn-p 为我工作。

    更新,在评论“已批准”代码后

    啊,可怕的建行。知道情况如何。 :( 如果 HtmlAgilityPack 没有通过,这里有一个替代解决方案,虽然它可能不是最好的 Regex 曾经写过。;)

    const string HTML = @"
    <div>
        <p class='img-desktop'>Paragraph</p>
        <div>
            <img src='somepath/desktop.jpg' class='img-desktop'>Desktop</img>
            <img src='somepath/mobile.jpg' class='img-mobile'>Mobile</img>
        </div>
        <div>
            <img src='somepath/desktop.jpg' alt='img-desktop' title='img-desktop' class=""img-desktop"">Desktop
    </IMG>
            <img src='somepath/mobile.jpg' class='img-mobile'>Mobile</img>
        </div>
    </div>";
    
    public void Go()
    {
        var regex = new Regex(
            // initial update
            // @"<img[^>]*class='?""?'?img-desktop""?[^>]*>.*?</img>",
    
            // after seeing accepted answer, noticed a bad copy/paste.
            // above works, but for readability should have been this:
            @"<img[^>]*class='?""?img-desktop""?'?[^>]*>.*?</img>",
            // and also noticed above can be shortened to this, which works too
            // @"<img[^>]*class=[^>]*img-desktop[^>]*>.*?</img>"
            RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline
        );
        Console.WriteLine(regex.Replace(HTML, ""));
    }
    

    Regex 为您提供了一点额外的余地,以防您处理的实际 HTML 与上面发布的 完全相同

    【讨论】:

    • 感谢您的回复!我也开始沿着这条路走,但因为它没有“被客户批准”,所以拒绝了它,这意味着它必须通过一个审批委员会。架构师相信它应该没问题,但我想探索其他选择......听起来没有任何选择:)我将尝试使用我拥有的更复杂的 html 并回复您。
    • 更新为Regex 替代品。
    • 我希望我能投票 50 次,谢谢!正则表达式路径是我目前拥有的,并且运行良好!!我将在星期一回来时去 HtmlAgilityPack,但至少我知道计划 B 有效,再次感谢您!!
    猜你喜欢
    • 2013-04-01
    • 1970-01-01
    • 2019-10-09
    • 2019-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    相关资源
    最近更新 更多