@@ -18,15 +18,24 @@ module Docx
1818 # puts d.text
1919 # end
2020 class Document
21- attr_reader :xml , :doc , :zip , :styles
21+
22+ # A path with * indicates that there are possibly multiple documents
23+ # matching that glob, eg. word/header1.xml, word/header2.xml
24+ DOCUMENT_PATHS = {
25+ doc : "word/document.xml" ,
26+ styles : "word/styles.xml" ,
27+ headers : "word/header*.xml" ,
28+ footers : "word/footer*.xml" ,
29+ numbering : "word/numbering.xml"
30+ }
31+
32+ attr_reader :xml , :doc , :zip , :styles , :headers , :footers , :numbering
2233
2334 def initialize ( path , &block )
2435 @replace = { }
2536 @zip = Zip ::File . open ( path )
26- @document_xml = @zip . read ( 'word/document.xml' )
27- @doc = Nokogiri ::XML ( @document_xml )
28- @styles_xml = @zip . read ( 'word/styles.xml' )
29- @styles = Nokogiri ::XML ( @styles_xml )
37+ extract_documents
38+
3039 if block_given?
3140 yield self
3241 @zip . close
@@ -57,6 +66,8 @@ def paragraphs
5766 def bookmarks
5867 bkmrks_hsh = Hash . new
5968 bkmrks_ary = @doc . xpath ( '//w:bookmarkStart' ) . map { |b_node | parse_bookmark_from b_node }
69+ bkmrks_ary += @headers . values . map { |xml_doc | xml_doc . xpath ( '//w:bookmarkStart' ) . map { |b_node | parse_bookmark_from b_node } } . flatten
70+ bkmrks_ary += @footers . values . map { |xml_doc | xml_doc . xpath ( '//w:bookmarkStart' ) . map { |b_node | parse_bookmark_from b_node } } . flatten
6071 # auto-generated by office 2010
6172 bkmrks_ary . reject! { |b | b . name == "_GoBack" }
6273 bkmrks_ary . each { |b | bkmrks_hsh [ b . name ] = b }
@@ -123,13 +134,49 @@ def replace_entry(entry_path, file_contents)
123134
124135 private
125136
137+ def extract_documents
138+ DOCUMENT_PATHS . each do |attr_name , path |
139+ if path . match /\* /
140+ extract_multiple_documents_from_globbed_path ( attr_name , path )
141+ else
142+ extract_single_document_from_path ( attr_name , path )
143+ end
144+ end
145+ end
146+
147+ def extract_single_document_from_path ( attr_name , path )
148+ if @zip . find_entry ( path )
149+ xml_doc = @zip . read ( path )
150+ self . instance_variable_set ( :"@#{ attr_name } " , Nokogiri ::XML ( xml_doc ) )
151+ end
152+ end
153+
154+ def extract_multiple_documents_from_globbed_path ( hash_attr_name , glob_path )
155+ files = @zip . glob ( glob_path ) . map { |h | h . name }
156+ filename_and_contents_pairs = files . map do |file |
157+ simple_file_name = file . sub ( /^word\/ / , "" ) . sub ( /\. xml$/ , "" )
158+ [ simple_file_name , Nokogiri ::XML ( @zip . read ( file ) ) ]
159+ end
160+ hash = Hash [ filename_and_contents_pairs ]
161+ self . instance_variable_set ( :"@#{ hash_attr_name } " , hash )
162+ end
163+
126164 #--
127165 # TODO: Flesh this out to be compatible with other files
128166 # TODO: Method to set flag on files that have been edited, probably by inserting something at the
129167 # end of methods that make edits?
130168 #++
131169 def update
132- replace_entry "word/document.xml" , doc . serialize ( :save_with => 0 )
170+ DOCUMENT_PATHS . each do |attr_name , path |
171+ if path . match /\* /
172+ self . instance_variable_get ( "@#{ attr_name } " ) . each do |simple_file_name , contents |
173+ replace_entry ( "word/#{ simple_file_name } .xml" , contents . serialize ( :save_with => 0 ) )
174+ end
175+ else
176+ xml_document = self . instance_variable_get ( "@#{ attr_name } " )
177+ replace_entry path , xml_document . serialize ( :save_with => 0 ) if xml_document
178+ end
179+ end
133180 end
134181
135182 # generate Elements::Containers::Paragraph from paragraph XML node
0 commit comments