Wie Text aus .docx-Datei in Tabellen finden und ersetzen?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
marlon_germany
User
Beiträge: 33
Registriert: Samstag 30. April 2022, 23:32

Ich habe im folgenden ein Skript, dass formatierten Text aus HTML Dateien liest, dann eine präparierte docx Datei öffnet
und bestimmte Wörter durch den HTML-Text der HTML-Dateien ersetzt und es als neue docx-Datei speichert.
Also wenn in der Word-Datei das Wort "{{ENTRY_1}}" steht, wird es durch den Inhalt der HTML-Datei "entry_1.html" ersetzt usw.

Soweit funktioniert das Skript ersteinmal.

Aber sobald die "Tags" wie "{{ENTRY_1}}","{{ENTRY_2}}" und "{{ENTRY_3}}" innerhalb einer Tabelle stehen, ist die "output.docx" nach dem Speichern leer!

Hier der Code, welcher für docx Dokumente funktioniert, wenn der Text nicht in Tabellen steht:

Code: Alles auswählen

import docx
from html.parser import HTMLParser
from tkinter import Button, Tk


#HTMLParser to parse the html files
class TKinterHTMLParser2(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.doc = docx.Document()
        self.paragraph = self.doc.add_paragraph()
        self.bold = False
        self.italic = False
        self.underline = False

    def handle_starttag(self, tag, attrs):
        if tag == 'b':
            self.bold = True
        if tag == 'i':
            self.italic = True
        if tag == 'u':
            self.underline = True

    def handle_endtag(self, tag):
        if tag == 'b':
            self.bold = False
        if tag == 'i':
            self.italic = False
        if tag == 'u':
            self.underline = False

    def handle_data(self, data):
        run = self.paragraph.add_run(data)
        run.bold = self.bold
        run.italic = self.italic
        run.underline = self.underline

    def save(self, filename):
        self.doc.save(filename)

class MyApp:
    def __init__(self, root):
        #button to start the conversion
        self.button = Button(root, text="Konvertieren", command=self.convert)
        self.button.pack()

  
    #function to convert the html files to docx
    def convert_html_to_docx(self):

        # variables for the template and output document
        template_doc = docx.Document('template.docx')
        output_doc = docx.Document()

        parser = TKinterHTMLParser2()

        # open the html files and parse them
        with open('entry_1.html') as f:
            parser.feed(f.read())
        entry1_doc = parser.doc

        parser = TKinterHTMLParser2()
        with open('entry_2.html') as f:
            parser.feed(f.read())
        entry2_doc = parser.doc

        parser = TKinterHTMLParser2()
        with open('entry_3.html') as f:
            parser.feed(f.read())
        entry3_doc = parser.doc

        # copy the template document to the output document
        for paragraph in template_doc.paragraphs:
            output_doc.add_paragraph(paragraph.text)

        # replace the placeholders with the parsed html files
        for paragraph in output_doc.paragraphs:
            if "{{ENTRY_1}}" in paragraph.text:
                
                paragraph.text = paragraph.text.replace("{{ENTRY_1}}", "")

                # copy the formatting from the parsed html file
                for p in entry1_doc.paragraphs:
                    for run in p.runs:
                            
                            new_run = paragraph.add_run(run.text)
                            new_run.bold = run.bold
                            new_run.italic = run.italic
                            new_run.underline = run.underline
                            new_run.font.name = run.font.name
                            new_run.font.size = run.font.size
                            new_run.font.color.rgb = run.font.color.rgb

            if "{{ENTRY_2}}" in paragraph.text:
                
                paragraph.text = paragraph.text.replace("{{ENTRY_2}}", "")

                # copy the formatting from the parsed html file
                for p in entry2_doc.paragraphs:
                    for run in p.runs:
                            new_run = paragraph.add_run(run.text)
                            new_run.bold = run.bold
                            new_run.italic = run.italic
                            new_run.underline = run.underline
                            new_run.font.name = run.font.name
                            new_run.font.size = run.font.size
                            new_run.font.color.rgb = run.font.color.rgb

            if "{{ENTRY_3}}" in paragraph.text:
                
                paragraph.text = paragraph.text.replace("{{ENTRY_3}}", "")

                # copy the formatting from the parsed html file
                for p in entry3_doc.paragraphs:
                    for run in p.runs:
                            new_run = paragraph.add_run(run.text)
                            new_run.bold = run.bold
                            new_run.italic = run.italic
                            new_run.underline = run.underline
                            new_run.font.name = run.font.name
                            new_run.font.size = run.font.size
                            new_run.font.color.rgb = run.font.color.rgb


        # save the output document
        output_doc.save('output.docx')


    # button command
    def convert(self):
        self.convert_html_to_docx()




root = Tk()
myapp = MyApp(root)
root.mainloop()
Wie ich mittlerweile rausgefunden habe, verarbeitet der Code nur die Abschnitte, die als Absätze markiert sind, nicht jedoch, wenn es innerhalb einer Tabelle im docx-Dokument vorkommt.Entsprechend werden die Tag-Wörter auch nicht in der "template.docx" Datei durch die Inhalte der HTML-Dateien ersetzt:

Ich habe versucht dafür den Code auf Folgendes zu ändern, jedoch leider ohne Erfolg:

Code: Alles auswählen

import docx
from html.parser import HTMLParser
from tkinter import Button, Tk


#class that converts the html to docx
class TKinterHTMLParser2(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.doc = docx.Document()
        self.paragraph = self.doc.add_paragraph()
        self.bold = False
        self.italic = False
        self.underline = False

    def handle_starttag(self, tag, attrs):
        if tag == 'b':
            self.bold = True
        if tag == 'i':
            self.italic = True
        if tag == 'u':
            self.underline = True

    def handle_endtag(self, tag):
        if tag == 'b':
            self.bold = False
        if tag == 'i':
            self.italic = False
        if tag == 'u':
            self.underline = False

    def handle_data(self, data):
        run = self.paragraph.add_run(data)
        run.bold = self.bold
        run.italic = self.italic
        run.underline = self.underline

    def save(self, filename):
        self.doc.save(filename)

class MyApp:
    def __init__(self, root):
        #button to start the conversion
        self.button = Button(root, text="Konvertieren", command=self.convert)
        self.button.pack()

  
    #function to convert the html to docx
    def convert_html_to_docx(self):
        parser = TKinterHTMLParser2()

        
        with open('entry_1.html') as f:
            parser.feed(f.read())
        entry1_doc = parser.doc

        parser = TKinterHTMLParser2()
        with open('entry_2.html') as f:
            parser.feed(f.read())
        entry2_doc = parser.doc

        parser = TKinterHTMLParser2()
        with open('entry_3.html') as f:
            parser.feed(f.read())
        entry3_doc = parser.doc

    
        template_doc = docx.Document('template.docx')
        output_doc = docx.Document()

        #copy the template docx to the output docx
        for paragraph in template_doc.paragraphs:
            output_doc.add_paragraph(paragraph.text)

        
        for table in template_doc.tables:
            for row in table.rows:
                for cell in row.cells:
                    for paragraph in cell.paragraphs:
                        if "{{ENTRY_1}}" in paragraph.text:
                            paragraph.text = paragraph.text.replace("{{ENTRY_1}}", "")

                            for paragraph in entry1_doc.paragraphs:
                                for run in paragraph.runs:
                                    new_run = paragraph.add_run(run.text)
                                    new_run.bold = run.bold
                                    new_run.italic = run.italic
                                    new_run.underline = run.underline
                                    new_run.font.name = run.font.name
                                    new_run.font.size = run.font.size
                                    new_run.font.color.rgb = run.font.color.rgb


                        elif "{{ENTRY_2}}" in paragraph.text:
                            paragraph.text = paragraph.text.replace("{{ENTRY_2}}", "")

                            for paragraph in entry2_doc.paragraphs:
                                for run in paragraph.runs:
                                    new_run = paragraph.add_run(run.text)
                                    new_run.bold = run.bold
                                    new_run.italic = run.italic
                                    new_run.underline = run.underline
                                    new_run.font.name = run.font.name
                                    new_run.font.size = run.font.size
                                    new_run.font.color.rgb = run.font.color.rgb

                        elif "{{ENTRY_3}}" in paragraph.text:
                            paragraph.text = paragraph.text.replace("{{ENTRY_3}}", "")

                            for paragraph in entry3_doc.paragraphs:
                                for run in paragraph.runs:
                                    new_run = paragraph.add_run(run.text)
                                    new_run.bold = run.bold
                                    new_run.italic = run.italic
                                    new_run.underline = run.underline
                                    new_run.font.name = run.font.name
                                    new_run.font.size = run.font.size
                                    new_run.font.color.rgb = run.font.color.rgb


                   
        output_doc.save('output.docx')
        



    #function to start the conversion
    def convert(self):
        self.convert_html_to_docx()




root = Tk()
myapp = MyApp(root)
root.mainloop()
Ich habe im "template.docx" Dokument, Text innerhalb als auch außerhalb von Tabellen stehen und möchte das er gefunden wird, dann ersetzt durch den HTML-Text und als "output.docx" gespeichert wird. Natürlich soll auch alles andere was im "template.docx" Dokument steht und nichts mit Tag-Wörtern zu tun hat in die "output.docx" übernommen werden. Also irgendein Text der normal, in fett, unterstrichen, kursiv oder farblich markiert ist.

Mir ist nämlich außerdem auch aufgefallen, dass jegliche Art von Formatierungen im "template.docx" nicht in die "output.docx" übernommen werden.
In dem Fall habe ich:
-farblich markierten Text
-Text der mit dem Effekt "Texthervorherbungsfarbe" markiert ist
-und Text in fett, kursiv, oder unterstrichen

In der Output-Datei ist der zuvor formartierte Text aus der "template.docx" Datei dann leider nur noch unformartiert.

Das einzige was funktioniert ist:
-dass formatierter Text aus den HTML-Dateien auch in die "output.docx" Datei formartiert übernommen wird
-und dass Tags wie "{{ENTRY_1}}" erfolgreich ersetzt werden, solange sie nicht in einer Tabelle stehen.

Wie muss der Code aussehen, damit das alles funktioniert?

Liebe Grüße,
Marlon
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass das in irgendeiner GUI läuft, ist völlig nebensächlich, den ganzen Tkinter-Kram hättest Du also in Deiner Frage weglassen können. Warum heißt die Klasse TKinterHTMLParser2, wo sie doch gar nichts mit TKinter zu tun hat? Die 2 ist unsinnig.
Statt den selben Code dreimal zu kopieren benutzt man Listen und Schleifen.

Du kopierst den Text der Paragraphen vom Template ins Ausgabe-Dokument. Natürlich gehen dabei alle Formatierungen verloren. Die ganze Kopiererei kannst Du Dir sparen, wenn Du gleich das Template-Dokument veränderst.
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass das in irgendeiner GUI läuft, ist völlig nebensächlich, den ganzen Tkinter-Kram hättest Du also in Deiner Frage weglassen können. Warum heißt die Klasse TKinterHTMLParser2, wo sie doch gar nichts mit TKinter zu tun hat? Die 2 ist unsinnig.
Statt den selben Code dreimal zu kopieren benutzt man Listen und Schleifen.

Du kopierst den Text der Paragraphen vom Template ins Ausgabe-Dokument. Natürlich gehen dabei alle Formatierungen verloren. Die ganze Kopiererei kannst Du Dir sparen, wenn Du gleich das Template-Dokument veränderst.
marlon_germany
User
Beiträge: 33
Registriert: Samstag 30. April 2022, 23:32

Sirius3 hat geschrieben: Montag 12. Dezember 2022, 08:54 Dass das in irgendeiner GUI läuft, ist völlig nebensächlich, den ganzen Tkinter-Kram hättest Du also in Deiner Frage weglassen können. Warum heißt die Klasse TKinterHTMLParser2, wo sie doch gar nichts mit TKinter zu tun hat? Die 2 ist unsinnig.
Statt den selben Code dreimal zu kopieren benutzt man Listen und Schleifen.

Du kopierst den Text der Paragraphen vom Template ins Ausgabe-Dokument. Natürlich gehen dabei alle Formatierungen verloren. Die ganze Kopiererei kannst Du Dir sparen, wenn Du gleich das Template-Dokument veränderst.
Oh, Super! Da hätte ich mal selbst drauf kommen können.
Ich habe nun die Zeile: "output_doc = docx.Document()" gelöscht
und beim speichern die "template_doc" Variable benutzt. Jetzt bleibt
die Formatierung erhalten. Vielen Dank!

Der Name "TKinterHTMLParser2" kommt daher, weil ich eine andere Tkinter-App habe, wo
ich ebenfalls eine andere Klasse mit dem Namen "TKinterHTMLParser1" habe, welche eine andere Funktion hat.
Ich habe die "TKinterHTMLParser2" Klasse heraus kopiert und zur Demonstration hier eingefügt. Sorry für die
Verwirrung.

Das Durchsuchen der Tabellen klappt jetzt auch.
Allerdings nur wenn ich vorher weiß, dass z.B. "{{ENTRY_1}}" außerhalb einer Tabelle steht
und "{{ENTRY_2}}" innerhalb einer Tabelle. Ich habe also die Schleife, die Paragraphen nach einem speziellen Wort durchsucht:

Code: Alles auswählen

for paragraph in template_doc.paragraphs:
            if "{{ENTRY_1}}" in paragraph.text:

        
                paragraph.text = paragraph.text.replace("{{ENTRY_1}}", "")

                
                for p in entry1_doc.paragraphs:
                    for run in p.runs:
                            new_run = paragraph.add_run(run.text)
                            new_run.bold = run.bold
                            new_run.italic = run.italic
                            new_run.underline = run.underline
                            new_run.font.name = run.font.name
                            new_run.font.size = run.font.size
                            new_run.font.color.rgb = run.font.color.rgb
und hänge dann die zweite Schleife dran, die in Tabellen nach dem speziellen Wort "{{ENTRY_2}}" sucht:

Code: Alles auswählen

for table in template_doc.tables:
            
            for row in table.rows:
                for cell in row.cells:
                    
                    if "{{ENTRY_2}}" in cell.text:
                        # Ersetzen des Platzhalters mit dem Text
                        cell.text = cell.text.replace("{{ENTRY_2}}", "")
                       
                        for p in entry2_doc.paragraphs:
                            for run in p.runs:
                                new_run = cell.add_paragraph().add_run(run.text)
                                new_run.bold = run.bold
                                new_run.italic = run.italic
                                new_run.underline = run.underline
                                new_run.font.name = run.font.name
                                new_run.font.size = run.font.size
                                new_run.font.color.rgb = run.font.color.rgb 
Ich bin soweit eigentlich damit zufrieden, weil mein Problem damit gelöst ist.

Aber gibt es nicht die Möglichkeit, dass für ein Wort wie "{{ENTRY_3}}" automatisch innerhalb als auch außerhalb von Tabellen gefunden wird?

Vielleicht möchte ich irgendwann mal spontan eine schnelles Template erstellen, ohne für jedes "{{Wort}}" eine angepasste schleife zu schreiben.
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Nur weil Du anderswo eine Klasse hast, die was mit Tkinter zu tun hat, muß diese hier nicht TKInterHTMLParser2 heißen. Wie schon geschrieben, kopiert man nicht den Code für ENTRY1,2,3 sondern benutzt passende Datenstrukturen.

Code: Alles auswählen

import docx
from html.parser import HTMLParser

class HtmlToDocxConverter(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.doc = docx.Document()
        self.paragraph = self.doc.add_paragraph()
        self.bold = False
        self.italic = False
        self.underline = False

    def handle_starttag(self, tag, attrs):
        if tag == 'b':
            self.bold = True
        if tag == 'i':
            self.italic = True
        if tag == 'u':
            self.underline = True

    def handle_endtag(self, tag):
        if tag == 'b':
            self.bold = False
        if tag == 'i':
            self.italic = False
        if tag == 'u':
            self.underline = False

    def handle_data(self, data):
        run = self.paragraph.add_run(data)
        run.bold = self.bold
        run.italic = self.italic
        run.underline = self.underline

    def save(self, filename):
        self.doc.save(filename)


def copy_paragraphs(source, destination):
    for paragraph in source.paragraphs:
        for run in paragraph.runs:
            new_run = destination.add_run(run.text)
            new_run.bold = run.bold
            new_run.italic = run.italic
            new_run.underline = run.underline
            new_run.font.name = run.font.name
            new_run.font.size = run.font.size
            new_run.font.color.rgb = run.font.color.rgb

def fill_template(template_filename, replacement_filenames):
    replacements = {}
    for placeholder, filename in replacement_filenames.items():
        converter = HtmlToDocxConverter()
        with open(filename) as f:
            parser.feed(f.read())
        replacements[placeholder] = converter.doc
    
    output_doc = docx.Document(template_filename)
    for paragraph in output_doc.paragraphs:
        for placeholder, replacement in replacements.items():
            if placeholder in paragraph.text:
                paragraph.text = paragraph.text.replace(placeholder, "")
                copy_paragraphs(replacement, paragraph)
    for table in output_doc.tables:
        for row in table.rows:
            for cell in row.cells:
                for placeholder, replacement in replacements.items():
                    if placeholder in cell.text:
                        cell.text = cell.text.replace(placeholder, "")
                        copy_paragraphs(replacement, cell.add_paragraph())
    return output_doc
    

output_doc = fill_template("template.docx", {
    "{{ENTRY_1}}": "entry1.html",
    "{{ENTRY_2}}": "entry2.html",
    "{{ENTRY_3}}": "entry3.html",
})
einfachTobi
User
Beiträge: 492
Registriert: Mittwoch 13. November 2019, 08:38

Als Hinweis: Ich habe brauchbare Ergebnisse mit python-docx-template erzielt. Vielleicht solltest du dir das mal ansehen, statt das Rad neu zu erfinden.
Das verwendet die Jinja2-Template-Engine. Hat also eine Syntax, wie du sie verwendet hast - allerdings musst du dich dann nicht selbst um das korrekte Einfügen kümmern.
marlon_germany
User
Beiträge: 33
Registriert: Samstag 30. April 2022, 23:32

@Sirius3: Danke für das Beispiel! Werde ich mir in Ruhe angucken, um
zu verstehen wie und was in deinem Code passiert.


@einfachTobi: Danke dir für den Tipp. Daran habe ich auch schon gedacht.
Und auch schon ausprobiert. Wenn ich docxtpl in Kombination mit BeautifulSoup benutze, schaffe ich es mit einem knappen Code den Text von den HTML-Dateien zu extrahieren und in die template.docx an die entsprechenden Stellen zu übertragen, egal ob Tabelle oder nicht.

Allerdings werden Formatierungen der HTML-Dateien wie "fett, kursiv, unterstrichen" nicht übernommen
und der Text ist dann unformatiert in der Output-Datei?

Und wenn ich versuche das zu regeln durch docxtpl in Kombination mit dem HTMLParser, lässt sich sich die docx-Datei nicht öffnen?
Es kommt die Fehlermeldung "Fehler beim Öffnen der Datei in Word"
marlon_germany
User
Beiträge: 33
Registriert: Samstag 30. April 2022, 23:32

PS: Ich habe gerade deinen Code getestet. Wenn ich die Output docx öffne, wurde nichts in der Datei ersetzt.
Da wo die Tags wie "ENTRY_1", "ENTRY_2", "ENTRY_3" plaziert waren, ist nichts mehr. Sie wurden nicht durch
die HTML-Daten ersetzt, sondern gelöscht. Das gilt für Wörter die innerhalb als auch außerhalb von Tabellen stehen.
Sirius3 hat geschrieben: Montag 12. Dezember 2022, 12:37 Nur weil Du anderswo eine Klasse hast, die was mit Tkinter zu tun hat, muß diese hier nicht TKInterHTMLParser2 heißen. Wie schon geschrieben, kopiert man nicht den Code für ENTRY1,2,3 sondern benutzt passende Datenstrukturen.

Code: Alles auswählen

import docx
from html.parser import HTMLParser

class HtmlToDocxConverter(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.doc = docx.Document()
        self.paragraph = self.doc.add_paragraph()
        self.bold = False
        self.italic = False
        self.underline = False

    def handle_starttag(self, tag, attrs):
        if tag == 'b':
            self.bold = True
        if tag == 'i':
            self.italic = True
        if tag == 'u':
            self.underline = True

    def handle_endtag(self, tag):
        if tag == 'b':
            self.bold = False
        if tag == 'i':
            self.italic = False
        if tag == 'u':
            self.underline = False

    def handle_data(self, data):
        run = self.paragraph.add_run(data)
        run.bold = self.bold
        run.italic = self.italic
        run.underline = self.underline

    def save(self, filename):
        self.doc.save(filename)


def copy_paragraphs(source, destination):
    for paragraph in source.paragraphs:
        for run in paragraph.runs:
            new_run = destination.add_run(run.text)
            new_run.bold = run.bold
            new_run.italic = run.italic
            new_run.underline = run.underline
            new_run.font.name = run.font.name
            new_run.font.size = run.font.size
            new_run.font.color.rgb = run.font.color.rgb

def fill_template(template_filename, replacement_filenames):
    replacements = {}
    for placeholder, filename in replacement_filenames.items():
        converter = HtmlToDocxConverter()
        with open(filename) as f:
            parser.feed(f.read())
        replacements[placeholder] = converter.doc
    
    output_doc = docx.Document(template_filename)
    for paragraph in output_doc.paragraphs:
        for placeholder, replacement in replacements.items():
            if placeholder in paragraph.text:
                paragraph.text = paragraph.text.replace(placeholder, "")
                copy_paragraphs(replacement, paragraph)
    for table in output_doc.tables:
        for row in table.rows:
            for cell in row.cells:
                for placeholder, replacement in replacements.items():
                    if placeholder in cell.text:
                        cell.text = cell.text.replace(placeholder, "")
                        copy_paragraphs(replacement, cell.add_paragraph())
    return output_doc
    

output_doc = fill_template("template.docx", {
    "{{ENTRY_1}}": "entry1.html",
    "{{ENTRY_2}}": "entry2.html",
    "{{ENTRY_3}}": "entry3.html",
})
[/quote]
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

@marlon_germany: ich habe ja keine Testdaten, an denen ich das Testen könnte, so ein bißchen selbst auf Fehlersuche zu gehen, würde nicht schaden. Der Code soll einfach nur prinzipiell zeigen, wie man es eigentlich lösen würde.
marlon_germany
User
Beiträge: 33
Registriert: Samstag 30. April 2022, 23:32

Sirius3 hat geschrieben: Dienstag 13. Dezember 2022, 14:17 @marlon_germany: ich habe ja keine Testdaten, an denen ich das Testen könnte, so ein bißchen selbst auf Fehlersuche zu gehen, würde nicht schaden. Der Code soll einfach nur prinzipiell zeigen, wie man es eigentlich lösen würde.
Ok. Trotzem Vielen Dank!
einfachTobi
User
Beiträge: 492
Registriert: Mittwoch 13. November 2019, 08:38

marlon_germany hat geschrieben: Montag 12. Dezember 2022, 17:42 Allerdings werden Formatierungen der HTML-Dateien wie "fett, kursiv, unterstrichen" nicht übernommen
und der Text ist dann unformatiert in der Output-Datei?

Und wenn ich versuche das zu regeln durch docxtpl in Kombination mit dem HTMLParser, lässt sich sich die docx-Datei nicht öffnen?
Es kommt die Fehlermeldung "Fehler beim Öffnen der Datei in Word"
Es wird gem. Doku empfohlen die Formatierungen von Hand im Template per Word vorzunehmen. Das hat bisher bei mir auch gut funktioniert. Ändern sich die Formatierungen denn ständig, sodass du sie aus der HTML übernehmen musst? Falls ja, dann bliebe noch die Möglichkeit die HTML-Formatierung in RichText-Formatierungen zu übersetzen, welche dann wiederum ins Word-Format gebracht werden: https://docxtpl.readthedocs.io/en/latest/#richtext
marlon_germany
User
Beiträge: 33
Registriert: Samstag 30. April 2022, 23:32

Gute Idee, die Formatierung bereits davor einzutragen.Aber leider ändert sich die Formatierung permanent.
Nachdem ich jetzt mehrere Tage versuchte den letzten Feinschliff hinzubekommen... Nämlich dass Zeilenbrüche nicht gemacht werden sollen wenn z.B. 2 verschiedene
html tags in einer Zeile stehen. Und dass bestimme Zeilenumbrüche richtig funktionieren...

wenn die HTML so aussieht:
Museumbesuch

Heute waren wir im Museum
Dann wurde es fett

Und zum Schluss teils kursiv
sieht die Word-Datei so aus:
Museumbesuch
Heute waren wir im Museum
Dann wurde es
fett
Und zum Schluss
teils kursiv
...habe ich htmldocx (https://pypi.org/project/htmldocx/) entdeckt! Wie habe ich das nur übersehen können?!
Man kann mit dem Code:

Code: Alles auswählen

from htmldocx import HtmlToDocx

new_parser = HtmlToDocx()
new_parser.parse_html_file("input_file.html", "output_file.docx")
Perfekt eins zu eins HTML in docx umwandeln und speichern.

Allerdings habe ich jetzt noch die Hürde, dass ich es damit irgendwie nicht schaffe, die Wörter die bereits in einer "template.docx" stehen, durch die Inhalte der HTML-Dateien ersetzen zu lassen...durch Hilfe von Listen wie z.B.:

Code: Alles auswählen

files = {
    "{{ENTRY_1}}": "ENTRY_1.html",
    "{{ENTRY_2}}": "ENTRY_2.html",
    "{{ENTRY_3}}": "ENTRY_3.html",
}
Wenn jemand weißß, was ich da tun kann, wäre ich sehr dankbar!
einfachTobi hat geschrieben: Mittwoch 14. Dezember 2022, 14:52
marlon_germany hat geschrieben: Montag 12. Dezember 2022, 17:42 Allerdings werden Formatierungen der HTML-Dateien wie "fett, kursiv, unterstrichen" nicht übernommen
und der Text ist dann unformatiert in der Output-Datei?

Und wenn ich versuche das zu regeln durch docxtpl in Kombination mit dem HTMLParser, lässt sich sich die docx-Datei nicht öffnen?
Es kommt die Fehlermeldung "Fehler beim Öffnen der Datei in Word"
Es wird gem. Doku empfohlen die Formatierungen von Hand im Template per Word vorzunehmen. Das hat bisher bei mir auch gut funktioniert. Ändern sich die Formatierungen denn ständig, sodass du sie aus der HTML übernehmen musst? Falls ja, dann bliebe noch die Möglichkeit die HTML-Formatierung in RichText-Formatierungen zu übersetzen, welche dann wiederum ins Word-Format gebracht werden: https://docxtpl.readthedocs.io/en/latest/#richtext
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

Ja, das Paket verwendet quasi den selben Ansatz wie Du, nur etwas ausgefeilter.
Am einfachsten wäre es, wenn Du Dein Template auch in reinem HTML schreiben könntest.

Wie Du aber sicher schon in der Dokumentation gelesen hast, brauchst Du add_html_to_document bzw. add_html_to_cell um was zu einem bestehenden Dokument hinzuzufügen. Wenn Du innerhalb eines Paragraphen etwas einfügen möchtest, ist mußt Du halt auch paragraph auf diesen Paragraphen setzen.
marlon_germany
User
Beiträge: 33
Registriert: Samstag 30. April 2022, 23:32

Das Template in reinem HTML zu schreiben ist ebenfalls eine interessante Idee.
Werde ich aus Interesse ausprobieren, weil ich wissen möchte, ob sich die Template-HTML
dann problemlos mit dem Inhalt der anderen HTML-Dateien beschreiben lässt.

Mittlerweile habe ich endlich herausgefunden, wie auch die Textformatierung/Textanordnung
funktioniert. Dazu habe ich die Schleife noch bearbeitet:

Code: Alles auswählen

for p in entry1_doc.paragraphs:
                    new_paragraph = output_doc.add_paragraph()
                    style = output_doc.styles['No Spacing']
                    new_paragraph.style = style
                    for run in p.runs:
                           
                            new_run = new_paragraph.add_run(run.text)
                            new_run.bold = run.bold
                            new_run.italic = run.italic
                            new_run.underline = run.underline
                            new_run.font.name = run.font.name
                            new_run.font.size = run.font.size
                            new_run.font.color.rgb = run.font.color.rgb 
und die Funktion "def handle_starttag" mit:

Code: Alles auswählen

if tag == 'br':
            self.paragraph = self.doc.add_paragraph()
ergänzt...

und in der Funktion "def handle_data" mit:

Code: Alles auswählen

if data == "<br>":
            self.paragraph = self.doc.add_paragraph()
        else:
             run = self.paragraph.add_run(data)
             run.bold = self.bold
             run.italic = self.italic
             run.underline = self.underline
ergänzt.

Endlich!!! :)

Den Vorschlag "add_html_to_documen"t bzw. "add_html_to_cell" zu nutzen, habe ich nicht hinbekommen.
Wie auch immer. Danke nochmal für Alles!
Sirius3 hat geschrieben: Donnerstag 15. Dezember 2022, 08:17 Ja, das Paket verwendet quasi den selben Ansatz wie Du, nur etwas ausgefeilter.
Am einfachsten wäre es, wenn Du Dein Template auch in reinem HTML schreiben könntest.

Wie Du aber sicher schon in der Dokumentation gelesen hast, brauchst Du add_html_to_document bzw. add_html_to_cell um was zu einem bestehenden Dokument hinzuzufügen. Wenn Du innerhalb eines Paragraphen etwas einfügen möchtest, ist mußt Du halt auch paragraph auf diesen Paragraphen setzen.
Antworten