Python - Copiar apartados de un documento a otro conservando los estilos

Desarrollo de Macros y programación en UNO, usar las API, llamar programas externos...
Responder
JoTacoronte
Mensajes: 10
Registrado: Lun Oct 05, 2015 11:13 am

Python - Copiar apartados de un documento a otro conservando los estilos

Mensaje por JoTacoronte »

Buenas compañeros del foro.

He trabajado desde hace tiempo con macros en basic para Libre Office. Y como Mauricio siempre recomendaba python, desde hace un tiempo estoy haciendo cosas con ese lenguaje para las macros.
Estoy utilizando PySide6, para utilizar una aplicación de escritorio desde la que poder hacer llamadas a macros de Libre Office, la cosa funciona.

Pero estoy atascado desde hace días en una macro de python para Libre Office para copiar apartados de un documento conservando sus estilos:

Mi idea es copiar apartados de un documento a otro icluyendo sus estilos, entendiendo como apartado del documento el título de dicho apartado y su texto asociado, ilustraciones, etc.). Sé como controlar los documentos, pero no sé como seleccionar los apartados mencionados y copiar/pegar con sus correspondientes estilos.

He probado con cursores y puedo recorrer todos los títulos del documento, pongamos como ejemplo títulos de tipo "Título 2", buscando un texto de título2 en particular, por lo que deberé copiar desde ese título hasta justo antes de que comience el siguiente título. Pero con dichos cursores solo consigo copiar el texto.

Acudí a este tema del foro: https://forum.openoffice.org/en/forum/v ... hp?t=79540

Con lo que puedo copiar todo el contenido del documento (incluyendo estilos), y pegarlo con [dispatcher.executeDispatch(frame, ".uno:Paste", "", 0, ())]: ver ejemplo inferior

document = XSCRIPTCONTEXT.getDocument()
ctx = uno.getComponentContext()
sm = ctx.ServiceManager
dispatcher = sm.createInstanceWithContext("com.sun.star.frame.DispatchHelper", ctx)
frame = document.CurrentController.Frame
dispatcher.executeDispatch(frame, ".uno:SelectAll", "", 0, ())
dispatcher.executeDispatch(frame, ".uno:Copy", "", 0, ())
dispatcher.executeDispatch(frame, ".uno:GoToEndOfDoc", "", 0, ())
dispatcher.executeDispatch(frame, ".uno:Paste", "", 0, ())

Funciona por lo que parece que la copia con estilos es posible, ¿sabría alguien como podría seleccionar un apartado en concreto y pegarlo?

Aprovecho para preguntar si saben si Mauricio sigue manteniendo ZAZ EasyMacros para Python, la idea es buena, o si alguien conoce otro framework útil.

Lástima que no hay mucha información de macros en python.

Un saludo y gracias de antemano.
OpenOffice 4.1.1 - Windows 8.1 Pro x64
JoTacoronte
Mensajes: 10
Registrado: Lun Oct 05, 2015 11:13 am

Re: Python - Copiar apartados de un documento a otro conservando los estilos

Mensaje por JoTacoronte »

Perdón, se me pasó poner correctamente mi configuración:
7.4.7.2 (x64) / LibreOffice Community
Windows 10.0 Build 22621
OpenOffice 4.1.1 - Windows 8.1 Pro x64
FJCC-ES
Mensajes: 873
Registrado: Mié Mar 25, 2009 1:19 am
Ubicación: Colorado, USA

Re: Python - Copiar apartados de un documento a otro conservando los estilos

Mensaje por FJCC-ES »

Esta macro copia los primeros cuatro párrafos del archivo adjunto, incluyendo la imagen y los estilos, a un archivo nuevo.

Código: Seleccionar todo

Sub CopyAll
'seleccionar los parrafos
  oText = ThisComponent.Text
  oObj1 = oText.createTextCursor()
  oObj1.gotoEndOfParagraph(True)
  
  oObj1.gotoNextParagraph(True)
  oObj1.gotoEndOfParagraph(True)
  
  oObj1.gotoNextParagraph(True)
  oObj1.gotoEndOfParagraph(True)
  
  oObj1.gotoNextParagraph(True)
  oObj1.gotoEndOfParagraph(True)
  
  oCurrCntrl = ThisComponent.CurrentController
  oCurrCntrl.select(oObj1)
'copiar todo
  trans= oCurrCntrl.getTransferable()
'abrir un archivo nuevo
oDoc = StarDesktop.loadComponentFromURL( "private:factory/swriter", "_blank", 0, Array() )
'insertar el texto u imagen
oDoc.currentcontroller.insertTransferable(trans)
End Sub
Adjuntos
HeadingPicture.odt
(19.33 KiB) Descargado 145 veces
JoTacoronte
Mensajes: 10
Registrado: Lun Oct 05, 2015 11:13 am

Re: Python - Copiar apartados de un documento a otro conservando los estilos

Mensaje por JoTacoronte »

Muchas gracias por contestar tan pronto.
En cuanto tenga un momento lo pruebo.
Un saludo.
OpenOffice 4.1.1 - Windows 8.1 Pro x64
JoTacoronte
Mensajes: 10
Registrado: Lun Oct 05, 2015 11:13 am

Re: Python - Copiar apartados de un documento a otro conservando los estilos

Mensaje por JoTacoronte »

Buenas noches.

Siento no haber contestado antes, he estado bastante liado.

Muchísimas gracias FJCC-ES por el ejemplo. Funciona perfectamente.

He intentado sin éxito migrarlo a Python, utilizando ZAZ EasyMacro, del genio Mauricio Baeza: nota: disculpen si hay urls más actualizadas que esas. Son las más actuales que encontré.

Quedando el código: (abro el documento desde donde se copian los párrafos desde una aplicación en PySyde6)

Código: Seleccionar todo

import external.easymacro.easymacro as easy

# Abrir fichero de origen
pathFolderDocs = 'C:/temp/test/'
nameFile = 'HeadingPicture.odt'
pathDoc = pathFolderDocs + nameFile
docCurrent = easy.get_document(nameFile)
if docCurrent is None:
    easy.msgbox('El documento no está abierto. Se abrirá.')
    docCurrent = easy.open_doc(pathDoc)

# Crear selección
cursor = docCurrent.cursor
cursor.gotoEndOfParagraph(True)

cursor.gotoNextParagraph(True)
cursor.gotoEndOfParagraph(True)

cursor.gotoNextParagraph(True)
cursor.gotoEndOfParagraph(True)

cursor.gotoNextParagraph(True)
cursor.gotoEndOfParagraph(True)

oCurrCntrl = docCurrent.obj.CurrentController
selection = docCurrent.obj.CurrentController.Selection

# Crear documento en blanco y pegar el contenido
trans = oCurrCntrl.getTransferable()
dc = easy.new_doc('writer')
dc.obj.CurrentController.insertTransferable(trans)
1. Se abre correctamente el fichero de origen.
2. Creo que se copia la selección del cursor.
3. Se crea un documento en blanco, pero no logro que se pegue nada en el nuevo documento.

He intentado seguir las pautas para Python del código de FJCC-ES, pero algo se me está escapando.

Si a alguien se le ocurre algo sería de gran ayuda. O bien si he de hacerlo sin la librería mencionada.

Desde ya muchas gracias a la gente del foro.

P.D: Diossss, que poca información hay sobre Python para Libre Office.

Saludos.
OpenOffice 4.1.1 - Windows 8.1 Pro x64
FJCC-ES
Mensajes: 873
Registrado: Mié Mar 25, 2009 1:19 am
Ubicación: Colorado, USA

Re: Python - Copiar apartados de un documento a otro conservando los estilos

Mensaje por FJCC-ES »

Esta macro funciona bien en OpenOffice con el archivo HeadingPicture.odt.

Código: Seleccionar todo

def Copiar4Para():
  ctx = XSCRIPTCONTEXT.getComponentContext()
  smgr = ctx.ServiceManager
  StarDesktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
  ThisComponent = StarDesktop.loadComponentFromURL("file:///C:/Users/fjcc/Desktop/HeadingPicture.odt", "_blank", 0, tuple() )

  oText = ThisComponent.Text
  oObj1 = oText.createTextCursor()
  oObj1.gotoEndOfParagraph(True)
  
  oObj1.gotoNextParagraph(True)
  oObj1.gotoEndOfParagraph(True)
  
  oObj1.gotoNextParagraph(True)
  oObj1.gotoEndOfParagraph(True)
  
  oObj1.gotoNextParagraph(True)
  oObj1.gotoEndOfParagraph(True)
  
  oCurrCntrl = ThisComponent.CurrentController
  oCurrCntrl.select(oObj1)
#copiar todo
  trans= oCurrCntrl.getTransferable()
#abrir un archivo nuevo
  oDoc = StarDesktop.loadComponentFromURL( "private:factory/swriter", "_blank", 0, tuple() )
#insertar el texto u imagen
  oDoc.CurrentController.insertTransferable(trans)
JoTacoronte
Mensajes: 10
Registrado: Lun Oct 05, 2015 11:13 am

Re: Python - Copiar apartados de un documento a otro conservando los estilos

Mensaje por JoTacoronte »

Buenas.

De nuevo FJCC-ES, muchísimas gracias por tu ayuda, eres un crack. Siguiendo tu código ya funciona:

Código: Seleccionar todo

import external.easymacro.easymacro as easy

# Abrir fichero de origen y copiar párrafos
pathDoc = 'C:/temp/test/HeadingPicture.odt'
ThisComponent = easy.open_doc(pathDoc)
oText = ThisComponent.obj.Text
oObj1 = oText.createTextCursor()
oObj1.gotoEndOfParagraph(True)

oObj1.gotoNextParagraph(True)
oObj1.gotoEndOfParagraph(True)

oObj1.gotoNextParagraph(True)
oObj1.gotoEndOfParagraph(True)

oObj1.gotoNextParagraph(True)
oObj1.gotoEndOfParagraph(True)

oCurrCntrl = ThisComponent.obj.CurrentController
oCurrCntrl.select(oObj1)
trans= oCurrCntrl.getTransferable()

# Crear documento en blanco y pegar el contenido
dc = easy.new_doc('writer')
dc.obj.CurrentController.insertTransferable(trans)
Mi escenario es el de intentar automatizar la generación/gestión de documentos Libre Office Writer, a partir ciertos apartados que ya se han hecho en su día, y que sirven como plantilla (simplemente copiando y pegando apartados a voluntad). El usuario selecciona los apartados que quiere de una lista y la aplicación genera el documento.
Cada vez que se genere un nuevo apartado, puede añadirse a la mencionada lista.

Es una aplicación PySide6, con un entorno virtual Python 3.11.3, pero se supone que la versión de Libre Office que tengo instalada hace uso de Python 3.8.16.
Si uso directamente las macros desde Libre Office funcionan correctamente, pero si las llamo de la aplicación me da problemas, como por ejemplo el uso de la línea:
ctx = XSCRIPTCONTEXT.getComponentContext()

Que me canta el error: com.sun.star.uno.RuntimeException: Error during invoking function main in module test.py (<class 'NameError'>: name 'XSCRIPTCONTEXT' is not defined

Por eso me decanté por la librería ZAZ EasyMacro, de Mauricio Baeza, que si me funciona sin problemas.

A ratitos iré evoluciinando el código.

Gracias de nuevo y un saludo.
OpenOffice 4.1.1 - Windows 8.1 Pro x64
Responder