Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions docxtpl/subdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
import re


W14_ANCHOR_ID = (
"{http://schemas.microsoft.com/office/word/2010/wordml}anchorId"
)


class SubdocComposer(Composer):
def attach_parts(self, doc, remove_property_fields=True):
"""Attach docx parts instead of appending the whole document
Expand All @@ -29,6 +34,7 @@ def attach_parts(self, doc, remove_property_fields=True):
cprops.dissolve_fields(name)

self._create_style_id_mapping(doc)
self.renumber_ole_objects(doc)

for element in doc.element.body:
if isinstance(element, CT_SectPr):
Expand All @@ -49,6 +55,71 @@ def attach_parts(self, doc, remove_property_fields=True):
self.renumber_nvpicpr_ids()
self.fix_section_types(doc)

def renumber_ole_objects(self, doc):
state = getattr(self.doc.part, "_docxtpl_ole_id_state", None)
if state is None:
body = self.doc.element.body
state = {
"shape_ids": set(xpath(body, ".//v:shape/@id")),
"shape_index": 1025,
"object_ids": set(xpath(body, ".//o:OLEObject/@ObjectID")),
"object_index": 1,
"anchor_ids": {
element.get(W14_ANCHOR_ID).upper()
for element in body.iter()
if element.get(W14_ANCHOR_ID) is not None
},
"anchor_index": 1,
}
self.doc.part._docxtpl_ole_id_state = state

state["shape_ids"].update(
xpath(doc.element.body, ".//v:shape/@id")
)
for ole_object in xpath(doc.element.body, ".//o:OLEObject"):
old_shape_id = ole_object.get("ShapeID")
matching_shapes = [
shape
for shape in xpath(ole_object.getparent(), "./v:shape")
if (
old_shape_id is not None
and shape.get("id") == old_shape_id
)
]
if len(matching_shapes) == 1:
shape_id = self._next_ole_id(
state, "shape", lambda index: "_x0000_i%d" % index
)
matching_shapes[0].set("id", shape_id)
ole_object.set("ShapeID", shape_id)
if ole_object.get("ObjectID") is not None:
ole_object.set(
"ObjectID",
self._next_ole_id(
state, "object", lambda index: "_%d" % index
),
)

for element in doc.element.body.iter():
if element.get(W14_ANCHOR_ID) is not None:
element.set(
W14_ANCHOR_ID,
self._next_ole_id(
state, "anchor", lambda index: "%08X" % index
),
)

@staticmethod
def _next_ole_id(state, kind, formatter):
index_key = "%s_index" % kind
ids_key = "%s_ids" % kind
while formatter(state[index_key]) in state[ids_key]:
state[index_key] += 1
value = formatter(state[index_key])
state[index_key] += 1
state[ids_key].add(value)
return value

def add_diagrams(self, doc, element):
# While waiting docxcompose 1.3.3
dgm_rels = xpath(element, ".//dgm:relIds[@r:dm]")
Expand Down
Loading