55
66from .. import results , lists , zips
77from .document_xml import read_document_xml_element
8+ from .header_xml import (read_header_xml_element , read_footer_xml_element )
89from .content_types_xml import empty_content_types , read_content_types_xml_element
910from .relationships_xml import read_relationships_xml_element , Relationships
1011from .numbering_xml import read_numbering_xml_element , Numbering
@@ -27,12 +28,13 @@ def read(fileobj):
2728 zip_file ,
2829 part_paths = part_paths ,
2930 )
30-
3131 return results .combine ([
3232 _read_notes (read_part_with_body , part_paths ),
3333 _read_comments (read_part_with_body , part_paths ),
34+ _read_headers (read_part_with_body , part_paths ),
35+ _read_footers (read_part_with_body , part_paths )
3436 ]).bind (lambda referents :
35- _read_document (zip_file , read_part_with_body , notes = referents [0 ], comments = referents [1 ], part_paths = part_paths )
37+ _read_document (zip_file , read_part_with_body , notes = referents [0 ], comments = referents [1 ], headers = referents [ 2 ], footers = referents [ 3 ], part_paths = part_paths )
3638 )
3739
3840
@@ -43,6 +45,8 @@ class _PartPaths(object):
4345 endnotes = cobble .field ()
4446 footnotes = cobble .field ()
4547 numbering = cobble .field ()
48+ headers = cobble .field ()
49+ footers = cobble .field ()
4650 styles = cobble .field ()
4751
4852
@@ -55,21 +59,24 @@ def _find_part_paths(zip_file):
5559 _find_relationships_path_for (document_filename ),
5660 )
5761
58- def find (name ):
62+ def find (name , multiple = False ):
5963 return _find_part_path (
6064 zip_file = zip_file ,
6165 relationships = document_relationships ,
6266 relationship_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/" + name ,
6367 fallback_path = "word/{0}.xml" .format (name ),
6468 base_path = zips .split_path (document_filename )[0 ],
69+ multiple = multiple
6570 )
66-
71+
6772 return _PartPaths (
6873 main_document = document_filename ,
6974 comments = find ("comments" ),
7075 endnotes = find ("endnotes" ),
7176 footnotes = find ("footnotes" ),
7277 numbering = find ("numbering" ),
78+ headers = find ("header" , multiple = True ),
79+ footers = find ("footer" , multiple = True ),
7380 styles = find ("styles" ),
7481 )
7582
@@ -88,7 +95,7 @@ def _find_document_filename(zip_file, relationships):
8895 raise IOError ("Could not find main document part. Are you sure this is a valid .docx file?" )
8996
9097
91- def _find_part_path (zip_file , relationships , relationship_type , base_path , fallback_path ):
98+ def _find_part_path (zip_file , relationships , relationship_type , base_path , fallback_path , multiple = False ):
9299 targets = [
93100 zips .join_path (base_path , target ).lstrip ("/" )
94101 for target in relationships .find_targets_by_type (relationship_type )
@@ -97,7 +104,7 @@ def _find_part_path(zip_file, relationships, relationship_type, base_path, fallb
97104 if len (valid_targets ) == 0 :
98105 return fallback_path
99106 else :
100- return valid_targets [0 ]
107+ return valid_targets if multiple else valid_targets [0 ]
101108
102109
103110def _read_notes (read_part_with_body , part_paths ):
@@ -111,7 +118,6 @@ def _read_notes(read_part_with_body, part_paths):
111118 lambda root , body_reader : read_endnotes_xml_element (root , body_reader = body_reader ),
112119 default = _empty_result ,
113120 )
114-
115121 return results .combine ([footnotes , endnotes ]).map (lists .flatten )
116122
117123
@@ -122,14 +128,42 @@ def _read_comments(read_part_with_body, part_paths):
122128 default = _empty_result ,
123129 )
124130
131+ def _read_headers (read_part_with_body , part_paths ):
132+ if type (part_paths .headers ) == str :
133+ header_paths = [part_paths .headers ]
134+ else :
135+ header_paths = part_paths .headers
136+
137+ headers = [
138+ read_part_with_body (header ,
139+ lambda root , body_reader : read_header_xml_element (root , body_reader = body_reader ),
140+ default = _empty_result ) for header in header_paths ]
141+ return [h for h in headers if h .value != []]
142+
143+
144+ def _read_footers (read_part_with_body , part_paths ):
145+ if type (part_paths .footers ) == str :
146+ footer_paths = [part_paths .footers ]
147+ else :
148+ footer_paths = part_paths .footers
149+
150+ footers = [
151+ read_part_with_body (footer ,
152+ lambda root , body_reader : read_footer_xml_element (root , body_reader = body_reader ),
153+ default = _empty_result ) for footer in footer_paths ]
154+
155+ return [f for f in footers if f .value != []]
156+
125157
126- def _read_document (zip_file , read_part_with_body , notes , comments , part_paths ):
158+ def _read_document (zip_file , read_part_with_body , notes , comments , headers , footers , part_paths ):
127159 return read_part_with_body (
128160 part_paths .main_document ,
129161 partial (
130162 read_document_xml_element ,
131163 notes = notes ,
132164 comments = comments ,
165+ headers = headers ,
166+ footers = footers
133167 ),
134168 )
135169
0 commit comments