从 html 创建 pdf 时,如何隐藏具有特定 class 的图像?

How do I hide images that have a certain class when creating a pdf from html?

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

我无法访问原始的 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" class.

的任何图片元素

我尝试过的:

我很快 运行 想不出如何处理这个...唯一的优点是 Html 进来的是一致的,因为工具正在其他地方生成它.所以,当一个用户 "adds an image to that html" 时,它的结构总是相同的,所以正则表达式和替换方法是可以接受的,尽管 CSS 方法会更受欢迎......

即使您是 Regex 专家并且您的输入如前所述是可预测的,解析 HTML 也很困难。更好更简单的方法是使用 tested/proven 解析器,几乎所有编程语言都提供该解析器。对于 .NET,它是 HtmlAgilityPack. If you know a bit of XPath,这与 CSS select 非常相似,它的设置非常简单,select 您要删除的特定节点:

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();
}

然后将解析后的 HTML 传递给 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 片段。

更新,在评论 'approved' 代码后:

啊,可怕的 CCB。知道那是怎么回事。 :( 如果 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 并非 如上所述。