Skip to content

Commit 84d926e

Browse files
committed
Implemented working solution in the OXML layer
1 parent dbd5993 commit 84d926e

File tree

3 files changed

+34
-23
lines changed

3 files changed

+34
-23
lines changed

docx/document.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,23 @@ class Document(ElementProxy):
2323
Use :func:`docx.Document` to open or create a document.
2424
"""
2525

26-
__slots__ = ('_part', '__body', '_Bookmarks')
26+
__slots__ = ('_part', '__body')
2727

2828
def __init__(self, element, part):
2929
super(Document, self).__init__(element)
3030
self._part = part
3131
self.__body = None
32-
self._Bookmarks = Bookmarks(self._element.body)
3332

3433
def start_bookmark(self, name):
3534
bookmarkstart = self._body.add_bookmarkStart(name)
3635
return Bookmark(bookmarkstart)
3736

38-
def end_bookmark(self):
39-
bookmarkend = self._body.add_bookmarkEnd()
37+
def end_bookmark(self, name=None):
38+
bookmarkend = self._body.add_bookmarkEnd(name)
4039
return Bookmark(bookmarkend)
4140

4241
def bookmarks(self):
43-
return self._Bookmarks # (self._element.body)
42+
return Bookmarks(self._element.body)
4443

4544
def add_heading(self, text='', level=1):
4645
"""
@@ -219,7 +218,6 @@ class _Body(BlockItemContainer):
219218
def __init__(self, body_elm, parent):
220219
super(_Body, self).__init__(body_elm, parent)
221220
self._body = body_elm
222-
self._parent = parent
223221

224222
def clear_content(self):
225223
"""
@@ -233,11 +231,15 @@ def clear_content(self):
233231
def add_bookmarkStart(self, name):
234232
bookmarkStart = self._body._add_bookmarkStart()
235233
bookmarkStart.name = name
236-
bookmarkStart.bmrk_id = self._parent._Bookmarks._next_id
234+
bookmarkStart.bmrk_id = bookmarkStart._next_id
237235
return Bookmark(bookmarkStart)
238236

239-
def add_bookmarkEnd(self):
240-
open_id = self._parent._Bookmarks._unclosed_bookmark
237+
def add_bookmarkEnd(self, name=None):
238+
241239
bookmarkEnd = self._body._add_bookmarkEnd()
242-
bookmarkEnd.bmrk_id = open_id
240+
if name is not None:
241+
bookmarkStart_id = bookmarkEnd.match_bookmarkstart(name)
242+
else:
243+
bookmarkStart_id = bookmarkEnd._next_id
244+
bookmarkEnd.bmrk_id = bookmarkStart_id
243245
return Bookmark(bookmarkEnd)

docx/oxml/bookmark.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,32 @@ class CT_BookmarkStart(BaseOxmlElement):
1616
"""
1717
name = RequiredAttribute('w:name', ST_String)
1818
bmrk_id = RequiredAttribute('w:id', ST_RelationshipId)
19+
20+
@property
21+
def _next_id(self):
22+
root = self.getroottree().getroot()
23+
return str(len(root.xpath('.//w:bookmarkStart')))
24+
1925

2026

2127
class CT_BookmarkEnd(BaseOxmlElement):
2228
"""
2329
The ``<w:bookmarkEnd>`` element
2430
"""
2531
bmrk_id = RequiredAttribute('w:id', ST_RelationshipId)
32+
33+
@property
34+
def _next_id(self):
35+
root = self.getroottree().getroot()
36+
return str(len(root.xpath('.//w:bookmarkStart')))
37+
38+
def match_bookmarkstart(self, name):
39+
"""Returns `w:bookmarkStart` element having matching name, None if not present."""
40+
root_element = self.getroottree().getroot()
41+
matching_bookmarkStarts = root_element.xpath(
42+
'.//w:bookmarkStart[@w:name=\'%s\']' % name
43+
)
44+
if not matching_bookmarkStarts:
45+
raise ValueError('Bookmark name not found')
46+
return None
47+
return matching_bookmarkStarts[0].bmrk_id

docx/text/bookmarks.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,6 @@ def _bookmarkEnds(self):
4747
def _next_id(self):
4848
return str(len(self._bookmarkStarts))
4949

50-
51-
@property
52-
def _unclosed_bookmark(self):
53-
open_b = set(Bookmark(bmrk)._id for bmrk in self._bookmarkStarts)
54-
closed = set(Bookmark(bmrk)._id for bmrk in self._bookmarkEnds)
55-
check = open_b - closed
56-
if len(self._bookmarkStarts) == 0:
57-
raise ValueError('BookmarkEnd requested without a bookmarkStart present')
58-
if len(check) == 0:
59-
raise ValueError('No open bookmark found')
60-
else:
61-
return check.pop()
62-
6350
class Bookmark(ElementProxy):
6451
def __init__(self, doc_element):
6552
super(Bookmark, self).__init__(doc_element)

0 commit comments

Comments
 (0)