2010-10-07 14 views
8

Sto usando una combinazione di rubyzip e nokogiri per modificare un file .docx. Sto usando rubyzip per decomprimere il file .docx e poi usando nokogiri per analizzare e cambiare il corpo del file word/document.xml ma sempre chiuderò rubyzip alla fine corrompe il file e non riesco ad aprirlo o riparalo. Ho decomprimere il file .docx sul desktop e controllare il file word/document.xml e il contenuto è aggiornato a quello che ho modificato, ma tutti gli altri file sono incasinati. Qualcuno potrebbe aiutarmi con questo problema? Qui è il mio codice:Come modificare docx con nokogiri e 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

Ciao Delvin, ho ricevuto lo stesso problema ma non sono in grado di risolverlo come suggeriva Eric. Come posso risolvere questo problema? Grazie – Rubyist

risposta

1

ci siamo imbattuti dall'altra parte della posta e non sanno nulla rubino o nokogiri ma ...

Sembra che si sta reziping i nuovi contenuti in modo non corretto. Non so rubyzip, ma è necessario un modo per dirgli di aggiornare la parola chiave/document.xml e quindi salvare nuovamente/rezip il file.

Sembra che tu stia semplicemente sovrascrivendo la voce con nuovi dati che ovviamente saranno di dimensioni diverse e rovineranno completamente il resto del file zip.

faccio un esempio per Excel in questo post Parse text file and create an excel report

che può essere utile anche se sto usando una biblioteca zip diversa e VB (Im ancora facendo esattamente quello che stai cercando di fare, il mio codice è di circa a metà strada verso il basso)

qui è la parte che si applica

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

ho incontrato lo stesso problema della corruzione con rubyzip la notte scorsa. L'ho risolto copiando tutto in un nuovo file zip, sostituendo i file secondo necessità.

Ecco la mia prova di lavoro di concetto:

#!/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 cosa fa/si riferisce la linea "w.force_settings"? – Simmo

+1

Non so come questo metodo sia stato tralasciato, ma è questo: https://gist.github.com/ericmason/7200421 Anche qui è il file completo dell'ultima copia che ho: https: //gist.github. com/ericmason/7200448 –