Mailkit: Преобразование HtmlBody в pdf с помощью iTextSharp XMLWorker бросает «Документ не имеет страниц»

c# html-agility-pack itext mailkit xmlworker

Вопрос

Я пытаюсь преобразовать HtmlBody в сообщения электронной почты, которые я получаю с почтового сервера с помощью Mailkit, и выглядит так, как iTextSharp не очень нравится html, с которым я его передаю.

Мой метод хорошо работает с «образцовым» html-кодом, но я получаю The document has no pages сообщений об ошибках 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.

Вот ссылка на pastebin для проверки HtmlBody MimeMessage потому что я попал в лимит символов здесь.

Что мне не хватает? Благодарю.

EDIT: Я пытался использовать HTMLWorker (который устарел), и он нестабилен. Он работал с одним электронным письмом, но не с другими. Конечно, это не было решением, но в итоге он создал pdf-файл от Mailkit, который был «чем-то».

Принятый ответ

Похоже, вы столкнулись с двумя проблемами с HtmlBody :

  1. Это может быть простой текст.
  2. Когда [X] HTML, он не является корректным.

Каждый раз, когда есть вероятность, что вы имеете дело с строкой, которая не является хорошо сформированным XML, лучше всего использовать парсер, такой как HtmlAgilityPack, чтобы очистить беспорядок. Вот простой вспомогательный метод, использующий XPath для покрытия обоих вышеперечисленных вопросов, и ОБНОВЛЕНО на основе комментариев для удаления HtmlCommentNode которые HtmlCommentNode с iText XML Worker:

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


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow