2010-10-07 69 views
8

J'utilise une combinaison de rubyzip et de nokogiri pour éditer un fichier .docx. J'utilise rubyzip pour décompresser le fichier .docx, puis en utilisant nokogiri pour analyser et changer le corps du fichier word/document.xml mais chaque fois que je ferme rubyzip à la fin, il corrompt le fichier et je ne peux pas l'ouvrir ou répare le. Je décompresser le fichier .docx sur le bureau et vérifier le fichier word/document.xml et le contenu est mis à jour à ce que je l'ai changé, mais tous les autres fichiers sont foirés. Quelqu'un pourrait-il m'aider avec ce problème? Voici mon code:Comment modifier docx avec nokogiri et 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

Bonjour Delvin, j'ai eu le même problème mais je ne suis pas capable de le résoudre comme Eric l'a suggéré. Comment puis-je résoudre ce problème? Merci – Rubyist

Répondre

1

je suis tombé en face de la poste et ne savent rien de rubis ou nokogiri mais ...

Il semble que vous reziping correctement le nouveau contenu. Je ne sais pas sur rubyzip, mais vous avez besoin d'un moyen de lui dire de mettre à jour l'entrée word/document.xml , puis resave/rezip le fichier.

Il semble que vous écrasez simplement l'entrée avec de nouvelles données qui, bien sûr, vont être de taille différente et vider totalement le reste du fichier zip.

Je donne un exemple pour exceller dans ce poste Parse text file and create an excel report

qui peut être utile même si je suis en utilisant une bibliothèque zip différente et VB (Im faire encore exactement ce que vous essayez de faire, mon code est sur le point à mi-chemin vers le bas)

est la partie ici qui applique

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

je suis tombé sur le même problème de corruption avec rubyzip hier soir. Je l'ai résolu en copiant tout dans un nouveau fichier zip, en remplaçant les fichiers si nécessaire.

Voilà ma preuve de travail de conception:

#!/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 quoi fait/fait référence la ligne 'w.force_settings'? – Simmo

+1

Je ne sais pas comment cette méthode a été omise, mais c'est: https://gist.github.com/ericmason/7200421 Voici également le fichier complet de la dernière copie que j'ai: https: //gist.github. com/ericmason/7200448 –