es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo puedo convertir una cadena Markdown a un documento DocX en Python?

Obtengo texto en formato markdown de mi API de la siguiente manera:

{
    name: 'Onur',
    surname: 'Gule',
    biography: '## Ordenadores
    Me gustan mucho los **ordenadores**.
    Quiero *ser* un ordenador.',
    membership: 1
}

El campo de la biografía incluye una cadena en formato markdown como se muestra arriba.

```markdown
## Ordenadores
Me gustan mucho los **ordenadores**.
Quiero *ser* un ordenador.

Quiero convertir este texto en formato markdown a una cadena en formato docx para mis informes.

En mi plantilla docx:

{{markdownText|mark2html}}

{{simpleText}}

Estoy utilizando el paquete python3 docxtpl para crear docx y funciona para textos sencillos. He intentado utilizar BeautifulSoup para convertir el markdown a texto docx, pero no funciona con estilos (negrita, cursiva, etc.). También he probado pandoc y funciona, pero solo crea un archivo docx, quiero añadir el texto markdown renderizado a un docx existente (mientras se crea).

Mi código actual es:

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) # Intenté con soup y pandoc...

def from_template(template):
    template = DocxTemplate(template)
    context = {
        'simpleText': 'Prueba de texto sencillo.',
        'markdownText': 'Prueba de texto en **markdown**.'
    } 
    jenv = jinja2.Environment()
    jenv.filters['markdown'] = safe_markdown
    jenv.filters["mark2html"] = mark2html
    template.render(context,jenv)
    template.save('nuevo_informe.docx')

Entonces, ¿cómo puedo añadir el texto markdown renderizado a un docx existente o mientras se crea, tal vez con un filtro de jinja2?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una posible solución sería modificar la función mark2html para que devuelva un objeto docx.Document en lugar de RichText. Luego, puedes usar el método add_paragraph del objeto docx.Document para agregar el texto markdown convertido como un nuevo párrafo en el documento.

    Aquí tienes una implementación de ejemplo:

    def mark2docx(valor):
        html = markdown.markdown(valor)
        soup = BeautifulSoup(html, features='html.parser')
        output = pypandoc.convert_text(valor, 'rtf', format='md')
        doc = docx.Document()
        for elem in soup.contents:
            if elem.name == 'p':
                paragraph = doc.add_paragraph()
                for child in elem.children:
                    if child.name == 'strong':
                        paragraph.add_run(child.text).bold = True
                    elif child.name == 'em':
                        paragraph.add_run(child.text).italic = True
                    else:
                        paragraph.add_run(child.text)
                paragraph.add_run('\n')
        return doc
    

    Luego, en tu función from_template, puedes usar este nuevo filtro en la plantilla:

    def from_template(template):
        template = DocxTemplate(template)
        contexto = {
            'simpleText': 'Prueba de texto simple.',
            'markdownText': 'Prueba de texto en markdown **negrita**.'
        }
        jenv = jinja2.Environment()
        jenv.filters['markdown'] = safe_markdown
        jenv.filters["mark2docx"] = mark2docx
        template.render(contexto, jenv)
        doc = template.docx
        markdown_doc = mark2docx(contexto["markdownText"])
        for elemento in markdown_doc.element.body:
            doc.element.body.append(elemento)
        template.save('nuevo_informe.docx')
    

    Aquí, estamos usando el método add_paragraph para crear un nuevo párrafo en el objeto docx.Document para cada elemento “ en la cadena HTML convertida. También estamos comprobando los elementos <strong> y <em> y aplicando estilos en negrita e itálica a las corridas correspondientes en el documento.

    Finalmente, para agregar el texto markdown renderizado al docx existente, estamos iterando sobre los elementos en el elemento body del documento mark2docx y añadiéndolos al elemento body de la plantilla docxtpl. Luego, guardamos el documento modificado como el nuevo informe.

Comments are closed.