2014-01-22 14 views
5

ich HTML-String bin Parsen des Code unten verwenden iTextSharp XMLWorker in meiner WPF-Anwendung mit:iTextSharp XMLWorker Parsing wirklich langsam

var css = ""; 
using (var htmlMS = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(html))) 
{      
    //Create a stream to read our CSS 
    using (var cssMS = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(css))) 
    {       
     //Get an instance of the generic XMLWorker 
     var xmlWorker = XMLWorkerHelper.GetInstance(); 

     //Parse our HTML using everything setup above 
     xmlWorker.ParseXHtml(writer, doc, htmlMS, cssMS, System.Text.Encoding.UTF8, fontProv);       
    } 
} 

Die Analyse funktioniert gut, aber es ist sehr langsam, es etwa 2 Sekunden dauert, die analysieren HTML. Für eine 50-seitige PDF-Datei dauert es etwa 2 Minuten. Ich verwende Inline-Styling in meiner HTML-Zeichenfolge. Ist das das natürliche Verhalten oder kann es optimiert werden?

+4

Ist Ihr HTML tief verschachtelt? Zum Beispiel, ist alles in einem riesigen DIV verpackt? In diesen Fällen muss der Parser (und sogar normale Desktop-Browser) den ganzen Weg bis zum Ende des Dokuments gehen, bevor es das erste Ding rendern kann. Benutzt du Tische? PDFs haben kein Konzept von Tabellen, also muss iText sie simulieren, die rechenintensiv sein können, wenn sie lang sind. Benutzt du Bilder? Wenn dies der Fall ist, muss iText die Bilder laden/herunterladen (abhängig davon, wie sie referenziert werden), was ebenfalls Zeit benötigt. –

+0

Ich habe noch keine Antwort, aber ich sehe, wie unglaublich langsam diese Bibliothek auch ist. Die meiste Zeit ist in der folgenden Methode in ParseXHtml gegessen: iTextSharp.text.FontFactoryImp.RegisterDirectories –

+0

Ich finde die XMLWorkerHelper-Instanz super langsam nur beim Ausführen meiner Anwendung im Debug-Modus. –

Antwort

6

Die Frage ist falsch in dem Sinne, dass es darauf hindeutet, dass das HTML-Parsing alles verlangsamt. Das ist nicht wahr. Der Engpass tritt auf, noch bevor das erste HTML-Snippet analysiert wird.

Sie sind die grundlegendsten Handvoll Zeilen Code mit Ihrem PDF von HTML zu erstellen, wie im ParseHtml Beispiel demonstriert:

public void createPdf(String file) throws IOException, DocumentException { 
    // step 1 
    Document document = new Document(); 
    // step 2 
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file)); 
    // step 3 
    document.open(); 
    // step 4 
    XMLWorkerHelper.getInstance().parseXHtml(writer, document, 
      new FileInputStream(HTML)); 
    // step 5 
    document.close(); 
} 

Dieser Code ist einfach, aber es führt intern eine Menge von Operationen, wie erklärt in den Kommentaren dieser anderen Frage: XMLWorkerHelper performance slow.

Die Registrierung von Schriftartenverzeichnissen erfordert viel Zeit. Sie können dies vermeiden, indem Sie Ihren eigenen FontProvider verwenden, wie im Beispiel ParseHtmlFonts getan.

public void createPdf(String file) throws IOException, DocumentException { 
    // step 1 
    Document document = new Document(); 

    // step 2 
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file)); 
    writer.setInitialLeading(12.5f); 

    // step 3 
    document.open(); 

    // step 4 

    // CSS 
    CSSResolver cssResolver = new StyleAttrCSSResolver(); 
    CssFile cssFile = XMLWorkerHelper.getCSS(new FileInputStream(CSS)); 
    cssResolver.addCss(cssFile); 

    // HTML 
    XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS); 
    fontProvider.register("resources/fonts/Cardo-Regular.ttf"); 
    fontProvider.register("resources/fonts/Cardo-Bold.ttf"); 
    fontProvider.register("resources/fonts/Cardo-Italic.ttf"); 
    fontProvider.addFontSubstitute("lowagie", "cardo"); 
    CssAppliers cssAppliers = new CssAppliersImpl(fontProvider); 
    HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers); 
    htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); 

    // Pipelines 
    PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer); 
    HtmlPipeline html = new HtmlPipeline(htmlContext, pdf); 
    CssResolverPipeline css = new CssResolverPipeline(cssResolver, html); 

    // XML Worker 
    XMLWorker worker = new XMLWorker(css, true); 
    XMLParser p = new XMLParser(worker); 
    p.parse(new FileInputStream(HTML)); 

    // step 5 
    document.close(); 
} 

In diesem Fall anweisen wir iText DONTLOOKFORFONTS, also eine enorme Menge an Zeit zu sparen. Anstatt iText nach Schriften zu suchen, teilen wir iText mit, welche Schriften wir im HTML verwenden werden.

+0

Vielen Dank für die Bereitstellung einer endgültigen Antwort von der Quelle - ich werde beginnen, meine Codebasis entsprechend zu erweitern. –

Verwandte Themen