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

时间:2016-02-05 05:15:17

标签: c# html css regex itextsharp

使用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
  • 将@media print {img.img-mobile:width:0; height:0}添加到CSS
  • 使用Regex查找包含该类的img元素,然后循环匹配,用空源替换源,并用新字符串替换该字符串的原始html(我的Regex没有抓取任何匹配,不幸的是)

            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”时,它的结构将始终相同,因此可以接受正则表达式和替换方法,尽管CSS方法会更受欢迎...

1 个答案:

答案 0 :(得分: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();
}

然后将解析后的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代码段为我工作。

在对“已批准”代码发表评论之后更新:

Aah,可怕的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不是完全,如上所述。