2010-10-07 21 views
8

Estoy usando una combinación de rubyzip y nokogiri para editar un archivo .docx. Estoy usando rubyzip para descomprimir el archivo .docx y luego usar nokogiri para analizar y cambiar el cuerpo del archivo word/document.xml pero cada vez que cierro rubyzip al final daña el archivo y no puedo abrirlo o repararlo Descomprimo el archivo .docx en el escritorio y verifico el archivo word/document.xml y el contenido se actualiza a lo que lo cambié pero todos los otros archivos están en mal estado. ¿Podría alguien ayudarme con este problema? Aquí está mi código:Cómo editar docx con nokogiri y rubyzip

require 'rubygems' 
require 'zip/zip' 
require 'nokogiri' 
zip = Zip::ZipFile.open("test.docx") 
doc = zip.find_entry("word/document.xml") 
xml = Nokogiri::XML.parse(doc.get_input_stream) 
wt = xml.root.xpath("//w:t", {"w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main"}).first 
wt.content = "New Text" 
zip.get_output_stream("word/document.xml") {|f| f << xml.to_s} 
zip.close 
+0

Hola Delvin, tengo el mismo problema pero no puedo resolverlo como sugirió Eric. Cómo puedo resolver este problema ? Gracias – Rubyist

Respuesta

1

Me encontré al otro lado del puesto y no saben nada de rubí o nokogiri pero ...

Parece que usted está reziping el nuevo contenido de forma incorrecta. No sé sobre rubyzip, pero necesita una forma de decirle que actualice la entrada word/document.xml y luego vuelva a guardar/volver a comprimir el archivo.

Parece que está sobrescribiendo la entrada con nuevos datos que, por supuesto, van a tener un tamaño diferente y arruinan por completo el resto del archivo comprimido.

Doy un ejemplo para sobresalir en este post Parse text file and create an excel report

que pueden ser de utilidad a pesar de que estoy usando una biblioteca postal diferente y VB (Im sigue haciendo exactamente lo que está tratando de hacer, mi código es de aproximadamente a mitad de camino hacia abajo)

aquí es la parte que se aplica

Using z As ZipFile = ZipFile.Read(xlStream.BaseStream) 
'Grab Sheet 1 out of the file parts and read it into a string. 
Dim myEntry As ZipEntry = z("xl/worksheets/sheet1.xml") 
Dim msSheet1 As New MemoryStream 
myEntry.Extract(msSheet1) 
msSheet1.Position = 0 
Dim sr As New StreamReader(msSheet1) 
Dim strXMLData As String = sr.ReadToEnd 

'Grab the data in the empty sheet and swap out the data that I want 
Dim str2 As XElement = CreateSheetData(tbl) 
Dim strReplace As String = strXMLData.Replace("<sheetData/>", str2.ToString) 
z.UpdateEntry("xl/worksheets/sheet1.xml", strReplace) 
'This just rezips the file with the new data it doesnt save to disk 
z.Save(fiRet.FullName) 
End Using 
12

me encontré con el mismo problema de la corrupción con rubyzip anoche. Lo resolví copiándolo todo en un nuevo archivo comprimido, reemplazando archivos según sea necesario.

Aquí está mi prueba de concepto de trabajo:

#!/usr/bin/env ruby 

require 'rubygems' 
require 'zip/zip' # rubyzip gem 
require 'nokogiri' 

class WordXmlFile 
    def self.open(path, &block) 
    self.new(path, &block) 
    end 

    def initialize(path, &block) 
    @replace = {} 
    if block_given? 
     @zip = Zip::ZipFile.open(path) 
     yield(self) 
     @zip.close 
    else 
     @zip = Zip::ZipFile.open(path) 
    end 
    end 

    def merge(rec) 
    xml = @zip.read("word/document.xml") 
    doc = Nokogiri::XML(xml) {|x| x.noent} 
    (doc/"//w:fldSimple").each do |field| 
     if field.attributes['instr'].value =~ /MERGEFIELD (\S+)/ 
     text_node = (field/".//w:t").first 
     if text_node 
      text_node.inner_html = rec[$1].to_s 
     else 
      puts "No text node for #{$1}" 
     end 
     end 
    end 
    @replace["word/document.xml"] = doc.serialize :save_with => 0 
    end 

    def save(path) 
    Zip::ZipFile.open(path, Zip::ZipFile::CREATE) do |out| 
     @zip.each do |entry| 
     out.get_output_stream(entry.name) do |o| 
      if @replace[entry.name] 
      o.write(@replace[entry.name]) 
      else 
      o.write(@zip.read(entry.name)) 
      end 
     end 
     end 
    end 
    @zip.close 
    end 
end 

if __FILE__ == $0 
    file = ARGV[0] 
    out_file = ARGV[1] || file.sub(/\.docx/, ' Merged.docx') 
    w = WordXmlFile.open(file) 
    w.force_settings 
    w.merge('First_Name' => 'Eric', 'Last_Name' => 'Mason') 
    w.save(out_file) 
end 
+0

¿A qué se refiere la línea 'w.force_settings'? – Simmo

+1

No estoy seguro de cómo se omitió ese método, pero es esto: https://gist.github.com/ericmason/7200421 También aquí está el archivo completo de la última copia que tengo: https: //gist.github. com/ericmason/7200448 –

Cuestiones relacionadas