【问题标题】:Mailkit: Converting HtmlBody to pdf using iTextSharp XMLWorker throws "The document has no pages"Mailkit:使用 iTextSharp XMLWorker 将 HtmlBody 转换为 pdf 会引发“文档没有页面”
【发布时间】:2017-07-23 11:46:02
【问题描述】:

我正在尝试使用 Mailkit 转换从邮件服务器收到的电子邮件的 HtmlBody,看起来 iTextSharp 并不喜欢我传递的 html。

我的方法适用于“示例”html 代码,但我收到 The document has no pages 错误消息,看起来当 html 不再是 html 时会抛出它。

public void GenerateHtmlFromBody(UniqueId uid)
{
    var email = imap.Inbox.GetMessage(uid);
    Byte[] bytes;

    using (var ms = new MemoryStream())
    {
        using (var doc = new Document())
        {
            using (var writer = PdfWriter.GetInstance(doc, ms))
            {
                doc.Open();

                //Sample HTML and CSS
                var example_html = @"<p>This <em>is </em><span class=""headline"" style=""text-decoration: underline;"">some</span> <strong>sample <em> text</em></strong><span style=""color: red;"">!!!</span></p>";
                var example_css = @".headline{font-size:200%}";

                using (var srHtml = new StringReader(email.HtmlBody))
                {
                    //Parse the HTML
                    iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
                }
                doc.Close();
            }
        }
        bytes = ms.ToArray();
    }
    var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "processedMailPdf.pdf");
    System.IO.File.WriteAllBytes(testFile, bytes);
}

我正在访问MimeMessage.HtmlBody 并进行调试,看起来它实际上是 html。

Here is a link to pastebin 用于检查MimeMessage 的 HtmlBody,因为我在这里达到了字符数限制。

我错过了什么?谢谢。

编辑:我尝试过使用 HTMLWorker(已弃用),但它并不稳定。它适用于一封电子邮件,但不适用于其他电子邮件。当然不是解决方案,但它最终从Mailkit生成了一个pdf,这是“东西”。

【问题讨论】:

  • 您是否尝试过其他电子邮件? html 看起来也很糟糕,我的编辑器甚至无法识别可折叠标签(VS Code)
  • 感谢您指出这一点。那是一封来自时事通讯的转发邮件。我刚刚尝试使用 Outlook 发送的典型 Outlook“自动测试”邮件来测试连接是否良好,但它不起作用。问题是 Mailkit 将其识别为 html,但查看 HtmlBody 它只是纯文本:o
  • 你应该尝试这样的事情:raw.githubusercontent.com/leemunroe/…
  • 问题可能是您使用的 XHTML 解析器仅适用于严格符合 XML 标准的 HTML(您在 pastebin 上的示例不适用)。您可以尝试使用 HtmlAgilityPack 来解析它,但我不确定这是否允许您将其转换为 PDF。
  • @mkl - 如果HtmlBody 有时确实是第二条评论中提到的纯文本,"&lt;html&gt;" + email.HtmlBody + "&lt;/html&gt;" 会抛出 Unhandled Exception: System.IO.IOException: The document has no pages.。使用 iTextSharp 和 XML Worker 版本 5.5.10 进行测试。也许你发现了一个错误......

标签: c# itext html-agility-pack mailkit xmlworker


【解决方案1】:

看起来您在使用 HtmlBody 时遇到了两个问题:

  1. 可能是纯文本。
  2. 当 [X]HTML 时,它不是格式正确。

任何时候您可能正在处理格式不正确的 XML 字符串,最好的办法是使用像 HtmlAgilityPack 这样的解析器来清理混乱。这是一个简单的辅助方法,使用 XPath 来涵盖上述两个问题,并基于 cmets UPDATED 删除破坏 iText XML Worker 的 HtmlCommentNodes:

string FixBrokenMarkup(string broken)
{
    HtmlDocument h = new HtmlDocument()
    {
        OptionAutoCloseOnEnd = true,
        OptionFixNestedTags = true,
        OptionWriteEmptyNodes = true
    };
    h.LoadHtml(broken);

    // UPDATED to remove HtmlCommentNode
    var comments = h.DocumentNode.SelectNodes("//comment()");
    if (comments != null) 
    {
        foreach (var node in comments) { node.Remove(); }
    }

    return h.DocumentNode.SelectNodes("child::*") != null
        //                            ^^^^^^^^^^
        // XPath above: string plain-text or contains markup/tags
        ? h.DocumentNode.WriteTo()
        : string.Format("<span>{0}</span>", broken);
}

为了完整起见,请编写生成 PDF 的代码。测试并使用您在上面提供的 pastebin 链接:

var fixedMarkup = FixBrokenMarkup(PASTEBIN);
// swap initialization to verify plain-text works too
// var fixedMarkup = FixBrokenMarkup("some text");

using (var stream = new MemoryStream())
{
    using (var document = new Document())
    {
        PdfWriter writer = PdfWriter.GetInstance(document, stream);
        document.Open();
        using (var stringReader = new StringReader(fixedMarkup))
        {
            XMLWorkerHelper.GetInstance().ParseXHtml(
                writer, document, stringReader
            );
        }
    }
    File.WriteAllBytes(OUTPUT, stream.ToArray());
}

【讨论】:

  • @Gonzo345 - 是的,没错。 HthmlAgilityPack 添加了缺失的结束标签,并且还尝试清理错误嵌套的标签。例如tdli
  • @Gonzo345 - 我今晚或明天去看看。 Exception 的奇怪描述 - 想知道它是如何出现在 iText 源代码中的......
  • @Gonzo345 - 哦,不得不处理专有的 Microsoft Office 疯狂的乐趣。 :( 无论如何,我得到一个不同的Exception - "iTextSharp.tool.xml.exceptions.RuntimeWorkerException: Invalid nested tag p found, expected closing tag ![endif]."。检查答案中更新的FixBrokenMarkup() 方法。使用您发布的pastebin sn-p 对我有用。
  • 我的意思是更新后的代码工作,而旧代码失败了,因为Exception 与你得到的相比不同。更新的代码有效,对吧?它对我 both 您问题中的 pastebin 以及您上面评论中的 pastebin 都有效....
  • @Gonzo345 - Word 在将文档转换为 HTML 时插入 &lt;![endif]&gt; 之类的内容,这会导致 Exception
【解决方案2】:

我发现,iTestSharp 的标签
有问题。 请改用

【讨论】:

  • 这是提到 xml 时其他答案和 cmets 的一个示例 - itext xmlworker 需要 xhtml,即每个开始元素都必须关闭。因此,单个&lt;br&gt; 无效,&lt;br/&gt; 有效。
猜你喜欢
  • 1970-01-01
  • 2013-06-28
  • 2016-07-10
  • 2012-04-24
  • 1970-01-01
  • 2015-03-21
  • 2011-01-22
  • 2012-04-03
  • 2011-05-06
相关资源
最近更新 更多