|
Página 4 de 5
|
¿Una Rutina Para Unir Varios .odt En Uno Solo?
Autor |
Mensaje |
Shell
Analista Programador
Registrado: Marzo 2010
Mensajes: 5278
Edad: 53 Ubicación: Al otro lado de la pantalla
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
Vuott:
Cuanto trabajo le espera a Shordi con este código a su regreso.
Saludos
=================== Gambas Básico
"No es un bug, es una característica no documentada"
|
#31 Lunes, 03 Julio 2017, 08:38 |
|
|
vuott
Analista Programador
Registrado: Agosto 2013
Mensajes: 2086
Edad: 60 Ubicación:
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
Bueno, con este ultimo codigo ahora el programa se vuelve " automático".
Tenemos dos Modulos.
El Modulo secundario se llama " CambioODT" y su codigo es:
Library "libzip:2.1.0"
Public Struct zip_stat
valid As Long
name As Pointer
index As Long
size As Long
comp_size As Long
mtime As Long
crc As Integer
comp_method As Short
encryption_method As Short
flags As Integer
End Struct
Private Const ZIP_CREATE As Integer = 1
' struct zip *zip_open(const char *, int, int *)
' Open zip archive.
Private Extern zip_open(path As String, flags As Integer, errorp As Pointer) As Pointer
' zip_int64_t zip_get_num_entries(struct zip *, int)
' Get number of files in archive.
Private Extern zip_get_num_entries(archive As Pointer, flags As Integer) As Long
' int zip_stat_index(struct zip *, int, int, struct zip_stat *)
' Get information about file by index.
Private Extern zip_stat_index(archive As Pointer, index As Integer, flags As Integer, zst As Zip_stat) As Integer
' struct zip_file * zip_fopen_index(struct zip *, int, int)
' Open file in zip archive for reading by index
Private Extern zip_fopen_index(archive As Pointer, fileno As Integer, flags As Integer) As Pointer
' ssize_t zip_fread(struct zip_file *, void *, size_t)
' Read from file.
Private Extern zip_fread(archive As Pointer, outbuf As Byte[], toread As Pointer) As Long
' struct zip_source *zip_source_file(struct zip *, const char *, zip_uint64_t, zip_int64_t)
' Create data source from a file.
Private Extern zip_source_file(archive As Pointer, fname As String, start As Long, len As Long) As Pointer
' const char *zip_get_name(struct zip *, zip_uint64_t, int)
' Get name of file by index.
Private Extern zip_get_name(zip As Pointer, index As Long, flags As Integer) As String
' int zip_replace(struct zip *, zip_uint64_t, struct zip_source *)
' Replace file in zip archive.
Private Extern zip_replace(archive As Pointer, index As Long, source As Pointer) As Integer
' int zip_fclose(struct zip_file *)
' Close file in zip archive.
Private Extern zip_fclose(zf As Pointer) As Integer
' int zip_close(struct zip *)
' Close zip archive.
Private Extern zip_close(archive As Pointer) As Integer
Public Procedure Extraccion(fileODT As String[], decomp As String)
Dim ruta As String
Dim z, zf As Pointer
Dim i, lun, c As Integer
Dim zs As New Zip_stat
Dim l As Long
Dim fl As File
Dim buf As Byte[]
For Each ruta In fileODT
buf = New Byte[64]
l = 0
z = zip_open(ruta, 0, 0)
If IsNull(z) Then Error.Raise("Imposible abrir un archivo '.odt' !")
For i = 0 To zip_get_num_entries(z, 0) - 1
If zip_stat_index(z, i, 0, zs) = 0 Then
zf = zip_fopen_index(z, i, 0)
If IsNull(zf) Then Error.Raise("Error a la función 'zip_fopen_index()' !")
If File.Name(String@(zs.name)) == "content.xml" Then
Inc c
fl = Open decomp &/ "xml" & CStr(c) & ".xml" For Create
While l < zs.size
lun = zip_fread(zf, buf, 64)
If lun < 0 Then Error.Raise("Error leyendo el archivo !")
buf.Write(fl, 0, lun)
l += lun
Wend
Endif
Endif
Next
fl.Close
zip_fclose(zf)
zip_close(z)
Next
End
Public Procedure Sustitucion(odt As String[])
Dim zip, src As Pointer
Dim err As Integer
Dim l As Long = -1
zip = zip_open(odt[0], ZIP_CREATE, VarPtr(err))
If zip = 0 Then
zip_close(zip)
Error.Raise("Imposible cargar el archivo .odt !")
Endif
src = zip_source_file(zip, "/tmp/content.xml", 0, 0)
If src = 0 Then
zip_close(zip)
Error.Raise("Imposibile crear el fuente de datos de el archivo .odt !")
Endif
Repeat
Inc l
Until zip_get_name(zip, l, 0) = "content.xml"
zip_replace(zip, l, src)
zip_close(zip)
End
El Modulo principal es:
Public Sub Main()
Dim s As String
Dim odt, xml As New String[]
' Especificamos rutas y nombres de todos los archivos .odt que queremos unir: ...en este ejemplo 3 archivos
odt = ["/tmp/archivo1.odt", "/tmp/archivo2.odt", "/tmp/archivo3.odt"]
' En el segundo argumento debe ser especificada la carpeta donde almacenaremos
' los archivos "content.xml", con sus nombres cambiados, de cada archivo .odt:
CambioODT.Extraccion(odt, "/tmp")
s = File.Load("/tmp/xml1.xml")
xml.Push(Scan(s, "*</office:document-content>*")[0])
s = File.Load("/tmp/xml2.xml")
xml.Push(Scan(s, "*</office:font-face-decls>*</office:document-content>*")[1])
s = File.Load("/tmp/xml3.xml")
xml.Push(Scan(s, "*</office:font-face-decls>*</office:document-content>*")[1])
File.Save("/tmp/content.xml", xml.Join(Null, Null) & "</office:document-content>")
' Sustitución del archivo original "content.xml", contenido en el archivo "/tmp/archivo1.odt", con el nuevo archivo "content.xml":
CambioODT.Sustitucion(odt)
End
Pax mihi nunc !
última edición por vuott el Martes, 04 Julio 2017, 16:25; editado 9 veces
|
#32 Martes, 04 Julio 2017, 00:37 |
|
|
tincho
Analista Programador
Registrado: Noviembre 2014
Mensajes: 2565
Edad: 48 Ubicación:
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
Estoy haciendo pruebas con tu codigo Vuott.
Saludos.
|
#33 Martes, 04 Julio 2017, 14:15 |
|
|
v3ctor
Analista Programador
Registrado: May 2013
Mensajes: 1786
Edad: 44 Ubicación: Uruguay
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
Vuott. eres un demonio de la programación!!!!!
que maestro heee!!!
=================== Software libre, programación libre, vida libre es la Public function Libertad()as Invendible
Proyectos: VisorRV1960,Taller2015,Tanteador
https://sourceforge.net/u/v3ctor-full/profile/
Blog: http://novatocodegambas.blogspot.com.uy/
|
#34 Martes, 04 Julio 2017, 15:20 |
|
|
vuott
Analista Programador
Registrado: Agosto 2013
Mensajes: 2086
Edad: 60 Ubicación:
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
Vuott. eres un demonio....
No puede ser eso, porque yo no soy... pythonista !
última edición por vuott el Martes, 04 Julio 2017, 16:31; editado 1 vez
|
#35 Martes, 04 Julio 2017, 16:27 |
|
|
shordi
Analista Programador
Registrado: Septiembre 2009
Mensajes: 4982
Edad: 64 Ubicación: Albacete
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
No es válido, me temo. Lo que hace LibreOffice es añadir un estilo CSS por cada cambio que se haga en el documento y llamarlo P1,P2, etc. si es un estilo de párrafa y T1,T2,etc. si es un estilo de fuente u otro tipo. Eso hace que los distintos documentos tengan distintos estilos con los mismos nombres. Antes del verano estuve viendo el tema un poco por encima y escribí el siguiente código:
Public Sub unirDocs(path As String, ardocs As String[], titulo As String)
Dim tmp, doc, meta, styles, texto, log, cad, tlog, unido, pathUnido As String
Dim n, i As Integer
Dim cTotal As New Collection
Dim v As Variant
Dim xm As XmlDocument
Dim nodo As XmlNode
Dim ar As String[]
tmp = File.Dir(Temp())
For Each doc In ardocs
If Exist(tmp &/ doc) Then Exec ["rm", "-r", tmp &/ doc] Wait
Shell "unzip \"" & path &/ doc & "\" -d " & tmp &/ doc To log
tlog &= log
Next
pathUnido = tmp & "/unido"
If Exist(pathUnido) Then Exec ["rm", "-r", pathUnido] Wait
Shell "cp -R \"" & tmp &/ ardocs[0] & "\" " & pathUnido Wait 'copiamos el primer documento para partir de él
unido = File.Load(pathUnido &/ "content.xml")
For n = 1 To ardocs.Max 'partimos del segundo documento
doc = File.Load(tmp &/ ardocs[n] &/ "content.xml")
unido = AddDoc(unido, doc)
doc = File.Load(tmp &/ ardocs[n] &/ "meta.xml")
AddMeta(cTotal, tmp &/ ardocs[n])
If Exist(tmp &/ ardocs[n] &/ "Pictures") Then
If Not Exist(pathUnido &/ "Pictures") Then Mkdir pathUnido &/ "Pictures"
ar = Dir(tmp &/ ardocs[n] &/ "Pictures")
For Each cad In ar
Copy tmp &/ ardocs[n] &/ "Pictures" &/ cad To pathUnido &/ "Pictures" &/ cad
Next
Endif
Next
'grabamos el nuevo contenido
Kill pathUnido &/ "content.xml"
File.Save(pathUnido &/ "content.xml", unido)
'sustituimos los valores de las estadísticas
meta = File.Load(pathUnido &/ "meta.xml")
xm = New XmlDocument(pathUnido &/ "meta.xml")
nodo = xm.GetElementsByTagName("meta:document-statistic")[0]
For Each v In nodo.Attributes
meta = Replace(meta, v.Name & "=\"" & v.value, v.Name & "=\"" & Str(v.value + cTotal[v.name]))
Next
Kill pathUnido &/ "meta.xml"
File.Save(pathUnido &/ "meta.xml", meta) 'grabamos las estadisticas acumuladas
' reconstruimos el fichero comprimido unificado
Try Kill "\"" & Settings["Entorno/path_salida"] &/ titulo & ".odt\""
texto = "cd " & pathUnido & ";zip -b " & tmp & " -r \"" & Settings["Entorno/path_salida"] &/ titulo & ".odt\" mimetype ." 'poniendo primero el mimetype
Shell texto To log
Catch
Message(Error.Text & "-" & Error.Where)
End
Public Function AddDoc(unido As String, doc As String) As String
Dim p, t, n, c, i As Integer
Dim etiq, styles, texto, cad As String
'
While InStr(unido, "style:name=\"P" & Str(p + 1) & "\"") > 0
Inc p
Wend 'calculamos el número de P y de T automáticos que tiene el documento unido hasta el momento
While InStr(unido, "style:name=\"T" & Str(t + 1) & "\"") > 0
Inc t
Wend
If InStr(doc, "<office:text>") > 0 Then
etiq = ""
Else
etiq = ">"
Endif
styles = mComun.Between(doc, "<office:automatic-styles>", "</office:automatic-styles>")
If InStr(doc, "<office:text>") = 0 Then
cad = mComun.between(doc, "<office:text", ">")
texto = mComun.Between(doc, "<office:text" & cad & ">", "</office:text")
'texto = mComun.Between(doc, "<office:text" & etiq, "</office:text>")
Else
texto = mComun.Between(doc, "<office:text>", "</office:text>")
Endif
n = p
For i = 1 To n
cad = "style:name=\"P" & Str(i) & "\""
If InStr(styles, cad) > 0 Then
Inc p
styles = Replace(styles, cad, "style:name=\"P" & Str(p) & "\"")
texto = Replace(texto, "text:style-name=\"P" & Str(i) & "\"", "text:style-name=\"P" & Str(p) & "\"")
Else
Break
Endif
Next
c = t
For i = 1 To c
If InStr(styles, "style:name=\"T" & Str(i) & "\"") > 0 Then
Inc t
styles = Replace(styles, "style:name=\"T" & Str(i) & "\"", "style:name=\"T" & Str(t) & "\"")
texto = Replace(texto, "text:style-name=\"T" & Str(i) & "\"", "text:style-name=\"T" & Str(t) & "\"")
Else
Break
Endif
Next
unido = Replace(unido, "</office:automatic-styles>", styles & "</office:automatic-styles>") ' y lo añadimos al del documento original
unido = Replace(unido, "</office:text>", texto & "</office:text>") ' y lo añadimos al del documento original
Return unido
Catch
Debug Error.text;; Error.where
End
(También empecé a codificar la misma función usando el componente gb.xml, pero está incompleta)
La función recibe el path, un array con los documentos a unir y el título, que es el nombre del documento unido. Acaba generando un documento que es la suma de todos los del array.
Hasta donde probé (no mucho, he de decir) funcionaba más o menos bien para documentos sencillos.
Sin embargo, cuando hablamos de muchos documentos (200 ó 300) y demás... pues no, como que todo petaba (no me acuerdo cómo).
La solución, creo, es la creación de un documento maestro en LibreOffice y el agregado de todos los demás documentos al mismo... pero no tengo ni idea de cómo hacer eso por código, de momento.
=================== No podemos regresar
|
#36 Miercoles, 20 Septiembre 2017, 05:09 |
|
|
vuott
Analista Programador
Registrado: Agosto 2013
Mensajes: 2086
Edad: 60 Ubicación:
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
No es válido, me temo.
El mio lo probaste ?
|
#37 Miercoles, 20 Septiembre 2017, 10:03 |
|
|
shordi
Analista Programador
Registrado: Septiembre 2009
Mensajes: 4982
Edad: 64 Ubicación: Albacete
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
No, me temo, ya te digo que leí el post cuando estaba en la playa sin ordenador...
Pero leyéndolo no veo que haya un traspaso y unión de estilos. ¿Si unes dos .odt que tengan distintos tipos de letra, fuente, tamaño etc. respeta los estilos de ambos?
Si es así, lo adoptaré... y te subiré la medalla a Medalla al Mérito Jedi Clase "A"
=================== No podemos regresar
|
#38 Miercoles, 20 Septiembre 2017, 14:43 |
|
|
vuott
Analista Programador
Registrado: Agosto 2013
Mensajes: 2086
Edad: 60 Ubicación:
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
Entonces solo tienes que probarlo.
|
#39 Miercoles, 20 Septiembre 2017, 14:59 |
|
|
shordi
Analista Programador
Registrado: Septiembre 2009
Mensajes: 4982
Edad: 64 Ubicación: Albacete
|
Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo?
Probado. Como sospechaba, no traslada los estilos.
Haz la prueba:
Crea un fichero archivo1.odt con una sóla línea y una fuente y tamaño de letra
Crea otro fichero archivo2.odt (no vale cambiar y grabar con otro nombre, hay que crearlo desde cero) y pon a la línea otra fuente y otro tamaño
Repite la operación con archivo3.odt.
Ejecuta tu código
Verás cómo el tipo de fuente de cada archivo se homogeneiza...
Es lo que contaba en mi comentario anterior:
Lo que hace LibreOffice es añadir un estilo CSS por cada cambio que se haga en el documento y llamarlo P1,P2, etc. si es un estilo de párrafo y T1,T2,etc. si es un estilo de fuente u otro tipo en cada uno de los documentos por tanto cada uno tiene un estilo llamado P1 que puede ser igual, o no, en los demás. Si no renombras esos estilos, se mezclarán.
=================== No podemos regresar
|
#40 Jueves, 21 Septiembre 2017, 07:25 |
|
|
|
Temas parecidos
Temas parecidos
|
Página 4 de 5
|
Usuarios navegando en este tema: 0 registrados, 0 ocultos y 1 invitado Usuarios registrados conectados: Ninguno
|
No puede crear mensajes No puede responder temas No puede editar sus mensajes No puede borrar sus mensajes No puede votar en encuestas No puede adjuntar archivos Puede descargar archivos No puede publicar eventos en el calendario
|
|
|
|
|