Obtengo un texto de descuento de mi API como este:
{ name:'Onur', surname:'Gule', biography:'## Computers I like **computers** so much. I wanna *be* a computer.', membership:1 }la columna de biografía incluye una cadena de descuento como la anterior.
## Computers I like **computers** so much. I wanna *be* a computer.Quiero tomar este texto de descuento y convertirlo en una cadena docx para mis informes.
En mi plantilla docx:
{{markdownText|mark2html}} {{simpleText}}Estoy usando el paquete python3 docxtpl para crear docx y funciona para textos simples.
Mi código actual:
import docx from docxtpl import DocxTemplate, RichText import markdown import jinja2 import markupsafe from bs4 import BeautifulSoup import pypandoc def safe_markdown(text): return markupsafe.Markup(markdown.markdown(text)) def mark2html(value): html = markdown.markdown(value) soup = BeautifulSoup(html, features='html.parser') output = pypandoc.convert_text(value,'rtf',format='md') return RichText(value) #tried soup and pandoc.. def from_template(template): template = DocxTemplate(template) context = { 'simpleText':'Simple text test.', 'markdownText':'Markdown **text** test.' } jenv = jinja2.Environment() jenv.filters['markdown'] = safe_markdown jenv.filters["mark2html"] = mark2html template.render(context,jenv) template.save('new_report.docx')Entonces, ¿cómo puedo agregar una reducción renderizada a un docx existente o durante la creación, tal vez con un filtro jinja2?
He seguido una estrategia perezosa, no muy eficiente, pero útil. Dado que tratar con docx es menos flexible que html , primero convertí el md de descuento a html , luego pasé de html a docx de esta manera:
from jinja2 import FileSystemLoader, Environment from pypandoc import convert_file, convert_text def md2html(md): return convert_text(md, 'html', format='md') def html2docx(file): return convert_file(f'{file}.html', 'docx', format='html', outputfile=f'{file}.docx') def from_template(template_file, f_out): context = { 'simpleText': 'Simple text test.', 'markdownText': 'Markdown **text** test.' } ldr = FileSystemLoader(searchpath='./') jenv = Environment(loader=ldr) jenv.filters["md2html"] = md2html template = jenv.get_template(template_file) html = template.render(context) print(html) with open(f'{f_out}.html', 'w') as fout: fout.write(html) fout.close() html2docx(f_out) if __name__ == '__main__': from_template('template.html.jinja', 'new_report') en cuanto al contenido de la plantilla, debe tomarse de una basada en html como esta:
<!DOCTYPE html> <html xml:lang="en-US" xmlns="http://www.w3.org/1999/xhtml" lang="en-US"> <head></head> <body> {{markdownText|md2html}} {{simpleText}} </body> </html> Lo guardé como template.html.jinja .
Tuve la tentación de investigar la contribución de @Mahrkeenerh, la API referida parece ser un proyecto bastante grande para aprender y comprender.
Lo resolví sin ningún atajo. Paso el descuento a html con beautifulSoup y luego proceso cada párrafo comprobando los nombres de sus etiquetas.
En mi plantilla de word:
{% if markdownText != None %} {% for mt in markdownText|mark2html %} {{mt}} {% endfor %} {% endif %}Mi etiqueta de plantilla:
def mark2html(value): if value == None: return '-' html = markdown.markdown(value) soup = BeautifulSoup(html, features='html.parser') paragraphs = [] global doc for tag in soup.findAll(True): if tag.name in ('p','h1','h2','h3','h4','h5','h6'): paragraphs.extend(parseHtmlToDoc(tag)) return paragraphsMi código para insertar docx:
def parseHtmlToDoc(org_tag): contents = org_tag.contents pars= [] for con in contents: if str(type(con)) == "<class 'bs4.element.Tag'>": tag = con if tag.name in ('strong',"h1","h2","h3","h4","h5","h6"): source = RichText("") if len(pars) > 0 and str(type(pars[len(pars)-1])) == "<class 'docxtpl.richtext.RichText'>": source = pars[len(pars)-1] source.add(con.contents[0], bold=True) else: source.add(con.contents[0], bold=True) pars.append(source) elif tag.name == 'img': source = tag['src'] imagen = InlineImage(doc, settings.MEDIA_ROOT+source) pars.append(imagen) elif tag.name == 'em': source = RichText("") source.add(con.contents[0], italic=True) pars.append(source) else: source = RichText("") if len(pars) > 0 and str(type(pars[len(pars)-1])) == "<class 'docxtpl.richtext.RichText'>": source = pars[len(pars)-1] pars.add(con) else: if org_tag.name == 'h2': source.add(con,bold=True,size=40) else: source.add(con) pars.append(source) # her zaman append? return parsProcesa etiquetas html como b, i, img, encabezados. Puede agregar más etiquetas para procesar. Lo resolví así y no necesita ninguna transformación de archivo adicional como html2docx, etc.