teste_docs / document /footnotes.py
gui-sparim's picture
Completa as equações de custo com legendas compactas
6bc379e verified
Raw History Blame Contribute Delete
5.55 kB
"""Notas de rodapé nativas, inclusive quando o documento já contém notas."""
from lxml import etree
from docx.oxml import OxmlElement, parse_xml
from docx.oxml.ns import qn
from docx.opc.constants import CONTENT_TYPE as CT, RELATIONSHIP_TYPE as RT
from docx.opc.packuri import PackURI
from docx.opc.part import Part, XmlPart
from docx.shared import Pt
from docx.text.paragraph import Paragraph
from copy import deepcopy
import re
from .public_text import public_text
def add_first_footnote(doc, pattern, text):
"""Attach a note immediately after the first body/table occurrence of a term."""
for element in doc.element.body.iter(qn('w:p')):
paragraph = Paragraph(element, doc._body)
if element.find('.//'+qn('m:oMath')) is not None:
display_text = ''.join(node.text or '' for node in element.iter()
if node.tag in (qn('w:t'),qn('m:t')))
if re.search(pattern,display_text):
# Word footnote references belong outside the math object.
# Keep the expression editable and place its marker after it.
return add_footnote(doc,paragraph,text)
match = re.search(pattern, paragraph.text)
if not match:
continue
offset = 0
for run in paragraph.runs:
end = offset + len(run.text)
if offset < match.end() <= end:
cut = match.end() - offset
tail = run.text[cut:]
run.text = run.text[:cut]
identifier = add_footnote(doc, paragraph, text)
marker = paragraph.runs[-1]._r
run._r.addnext(marker)
if tail:
remainder = OxmlElement('w:r')
if run._r.rPr is not None:
remainder.append(deepcopy(run._r.rPr))
content = OxmlElement('w:t')
content.text = tail
content.set(qn('xml:space'), 'preserve')
remainder.append(content)
marker.addnext(remainder)
return identifier
offset = end
return add_footnote(doc, paragraph, text)
return None
def order_footnotes(doc):
"""Keep IDs and stored note order aligned with their first body occurrence.
Notes can be attached retroactively to earlier terms. Align both orders so
Word and LibreOffice associate every visible number with the right text.
"""
try:
part = doc.part.part_related_by(RT.FOOTNOTES)
except KeyError:
return
root = parse_xml(part.blob)
notes = {n.get(qn('w:id')): n for n in root if int(n.get(qn('w:id'))) > 0}
refs = list(doc.element.body.iter(qn('w:footnoteReference')))
ordered_ids = list(dict.fromkeys(r.get(qn('w:id')) for r in refs))
ordered_ids += [key for key in notes if key not in ordered_ids]
mapping = {key: str(i+1) for i,key in enumerate(ordered_ids)}
for reference in refs:
reference.set(qn('w:id'),mapping[reference.get(qn('w:id'))])
for old_id in ordered_ids:
note = notes[old_id]
note.set(qn('w:id'),mapping[old_id])
root.append(note)
if isinstance(part,XmlPart):
part._element = root
else:
part._blob = etree.tostring(root,xml_declaration=True,encoding='UTF-8',standalone=True)
def add_footnote(doc, paragraph, text):
text = public_text(text)
try:
part = doc.part.part_related_by(RT.FOOTNOTES)
root = parse_xml(part.blob)
except KeyError:
root = OxmlElement('w:footnotes')
for identifier, kind in [(-1, 'separator'), (0, 'continuationSeparator')]:
note = OxmlElement('w:footnote')
note.set(qn('w:id'), str(identifier)); note.set(qn('w:type'), kind)
p = OxmlElement('w:p'); r = OxmlElement('w:r')
r.append(OxmlElement('w:'+kind)); p.append(r); note.append(p); root.append(note)
part = Part(PackURI('/word/footnotes.xml'), CT.WML_FOOTNOTES, b'', doc.part.package)
doc.part.relate_to(part, RT.FOOTNOTES)
identifier = max([0] + [int(n.get(qn('w:id'))) for n in root]) + 1
note = OxmlElement('w:footnote'); note.set(qn('w:id'), str(identifier))
p = OxmlElement('w:p'); props = OxmlElement('w:pPr')
spacing = OxmlElement('w:spacing'); spacing.set(qn('w:after'), '60')
props.append(spacing); p.append(props)
for marker, value in [('footnoteRef', None), ('t', ' '+text)]:
r = OxmlElement('w:r'); rp = OxmlElement('w:rPr')
font = OxmlElement('w:rFonts')
font.set(qn('w:ascii'), 'Arial'); font.set(qn('w:hAnsi'), 'Arial'); rp.append(font)
size = OxmlElement('w:sz'); size.set(qn('w:val'), '14'); rp.append(size)
if value is None:
vertical = OxmlElement('w:vertAlign'); vertical.set(qn('w:val'), 'superscript'); rp.append(vertical)
r.append(rp); element = OxmlElement('w:'+marker)
if value is not None:
element.text = value; element.set(qn('xml:space'), 'preserve')
r.append(element); p.append(r)
note.append(p); root.append(note)
if isinstance(part, XmlPart):
part._element = root
else:
part._blob = etree.tostring(root, xml_declaration=True, encoding='UTF-8', standalone=True)
run = paragraph.add_run(); run.font.superscript = True
run.font.size = Pt(7)
reference = OxmlElement('w:footnoteReference'); reference.set(qn('w:id'), str(identifier))
run._r.append(reference)
return identifier