Portal    Foro    Buscar    FAQ    Registrarse    Conectarse


Publicar nuevo tema  Responder al tema 
Página 4 de 5
Ir a la página Anterior  1, 2, 3, 4, 5  Siguiente
 
¿Una Rutina Para Unir Varios .odt En Uno Solo?
Autor Mensaje
Responder citando   Descargar mensaje  
Mensaje Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo? 
 
Vuott:

Cuanto trabajo le espera a Shordi con este código a su regreso.  vil_serpent  

Saludos
 




===================
Gambas Básico
"No es un bug, es una característica no documentada"
 
Shell - Ver perfil del usuarioEnviar mensaje privadoVisitar sitio web del usuario 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo? 
 
Bueno, con este ultimo codigo ahora el programa se vuelve "automático".   zomp

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 
vuott - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo? 
 
Estoy haciendo pruebas con tu codigo Vuott.

Saludos.
 



 
tincho - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje 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/
 
v3ctor - Ver perfil del usuarioEnviar mensaje privadoVisitar sitio web del usuario 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo? 
 
v3ctor escribió: [Ver mensaje]
Vuott. eres un demonio....

No puede ser eso, porque yo no soy... pythonista !    whistle
 



 
última edición por vuott el Martes, 04 Julio 2017, 16:31; editado 1 vez 
vuott - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje 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
 
shordi - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo? 
 
shordi escribió: [Ver mensaje]
No es válido, me temo.

El mio lo probaste ?
 



 
vuott - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje 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
 
shordi - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: ¿Una Rutina Para Unir Varios .odt En Uno Solo? 
 
Entonces solo tienes que probarlo.    
 



 
vuott - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje 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
 
shordi - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Mostrar mensajes anteriores:    
 

Publicar nuevo tema  Responder al tema  Página 4 de 5
Ir a la página Anterior  1, 2, 3, 4, 5  Siguiente

Usuarios navegando en este tema: 0 registrados, 0 ocultos y 1 invitado
Usuarios registrados conectados: Ninguno


 
Lista de permisos
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



  

 

cron