Skip to content

Commit 12a7df8

Browse files
committed
#5 Support for endnotes
We have support for footnotes but we need to be able to read endnotes also. Just like footnotes, endnotes are placed in separate file endnotes.xml. We need to parse it and store in similar to footnotes.
1 parent 9ab9484 commit 12a7df8

3 files changed

Lines changed: 75 additions & 2 deletions

File tree

ooxml/doc.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ def reset(self):
154154
self.elements = []
155155
self.relationships = {}
156156
self.footnotes = {}
157+
self.endnotes = {}
157158
self.numbering = {}
158159
self.abstruct_numbering = {}
159160
self.styles = StylesCollection()
@@ -290,6 +291,18 @@ def value(self):
290291
return self.rid
291292

292293

294+
class Endnote(Element):
295+
"Represents endnote element."
296+
297+
def __init__(self, rid):
298+
super(Endnote, self).__init__()
299+
300+
self.rid = rid
301+
302+
def value(self):
303+
return self.rid
304+
305+
293306
class TextBox(Element):
294307
"Represents TextBox element."
295308

ooxml/parse.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ def parse_footnote(document, container, elem):
196196
container.elements.append(foot)
197197

198198

199+
def parse_endnote(document, container, elem):
200+
"Parse the endnote element."
201+
202+
_rid = elem.attrib[_name('{{{w}}}id')]
203+
204+
note = doc.Endnote(_rid)
205+
container.elements.append(note)
206+
207+
199208
def parse_alternate(document, container, elem):
200209
txtbx = elem.find('.//'+_name('{{{w}}}txbxContent'))
201210
paragraphs = []
@@ -256,6 +265,11 @@ def parse_text(document, container, element):
256265
if foot is not None:
257266
parse_footnote(document, container, foot)
258267

268+
end = element.find(_name('{{{w}}}endnoteReference'))
269+
270+
if end is not None:
271+
parse_endnote(document, container, end)
272+
259273
sym = element.find(_name('{{{w}}}sym'))
260274

261275
if sym is not None:
@@ -522,6 +536,21 @@ def parse_footnotes(document, xmlcontent):
522536
document.footnotes[style.attrib[_name('{{{w}}}id')]] = p
523537

524538

539+
def parse_endnotes(document, xmlcontent):
540+
"""Parse endnotes document.
541+
542+
Endnotes are defined in file 'endnotes.xml'
543+
"""
544+
545+
endnotes = etree.fromstring(xmlcontent)
546+
document.endnotes = {}
547+
548+
for note in endnotes.xpath('.//w:endnote', namespaces=NAMESPACES):
549+
paragraphs = [parse_paragraph(document, para) for para in note.xpath('.//w:p', namespaces=NAMESPACES)]
550+
551+
document.endnotes[note.attrib[_name('{{{w}}}id')]] = paragraphs
552+
553+
525554
def parse_numbering(document, xmlcontent):
526555
"""Parse numbering document.
527556
@@ -590,6 +619,12 @@ def parse_from_file(file_object):
590619
except KeyError:
591620
logger.warning('Could not read footnotes.')
592621

622+
try:
623+
endnotes_content = file_object.read_file('endnotes.xml')
624+
parse_endnotes(document, endnotes_content)
625+
except KeyError:
626+
logger.warning('Could not read endnotes.')
627+
593628
try:
594629
numbering_content = file_object.read_file('numbering.xml')
595630
parse_numbering(document, numbering_content)

ooxml/serialize.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,9 @@ def get_style_fontsize(node):
347347
Font size as int number or 0 if it is not defined
348348
349349
"""
350-
if 'sz' in node.rpr:
351-
return int(node.rpr['sz']) / 2
350+
if hasattr(node, 'rpr'):
351+
if 'sz' in node.rpr:
352+
return int(node.rpr['sz']) / 2
352353

353354
return 0
354355

@@ -697,6 +698,27 @@ def serialize_footnote(ctx, document, el, root):
697698
return root
698699

699700

701+
def serialize_endnote(ctx, document, el, root):
702+
"Serializes endnotes."
703+
704+
footnote_num = el.rid
705+
706+
if el.rid not in ctx.endnote_list:
707+
ctx.endnote_id += 1
708+
ctx.endnote_list[el.rid] = ctx.endnote_id
709+
710+
footnote_num = ctx.endnote_list[el.rid]
711+
712+
note = etree.SubElement(root, 'sup')
713+
link = etree.SubElement(note, 'a')
714+
link.set('href', '#')
715+
link.text = u'{}'.format(footnote_num)
716+
717+
fire_hooks(ctx, document, el, note, ctx.get_hook('endnote'))
718+
719+
return root
720+
721+
700722
def serialize_table(ctx, document, table, root):
701723
"""Serializes table element.
702724
"""
@@ -907,6 +929,7 @@ def get_header(self, elem, style, node):
907929
doc.Break: serialize_break,
908930
doc.TextBox: serialize_textbox,
909931
doc.Footnote: serialize_footnote,
932+
doc.Endnote: serialize_endnote,
910933
doc.Symbol: serialize_symbol
911934
},
912935

@@ -997,6 +1020,8 @@ def reset(self):
9971020

9981021
self.footnote_id = 0
9991022
self.footnote_list = {}
1023+
self.endnote_id = 0
1024+
self.endnote_list = {}
10001025

10011026
self.in_list = []
10021027
self.header = self.options['header']()

0 commit comments

Comments
 (0)