Skip to content

Commit 2e9971f

Browse files
committed
Implemented working solution in the OXML layer
1 parent 464667a commit 2e9971f

File tree

6 files changed

+69
-31
lines changed

6 files changed

+69
-31
lines changed

docx/document.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from .section import Section, Sections
1515
from docx.shared import ElementProxy, Emu
1616
from docx.text.bookmarks import Bookmark, Bookmarks
17-
from docx.oxml.xmlchemy import BaseOxmlElement, ZeroOrOne, ZeroOrMore
17+
from docx.oxml.xmlchemy import ZeroOrOne, ZeroOrMore
1818

1919

2020
class Document(ElementProxy):
@@ -30,16 +30,16 @@ def __init__(self, element, part):
3030
self._part = part
3131
self.__body = None
3232

33-
def bookmark(self):
34-
return Bookmarks(self._element.body)
35-
# def add_bookmark_start(self, name):
36-
# paragraph = self.add_paragraph()
37-
# return paragraph.add_bookmark_start(id, name)
33+
def start_bookmark(self, name):
34+
bookmarkstart = self._body.add_bookmarkStart(name)
35+
return Bookmark(bookmarkstart)
36+
37+
def end_bookmark(self, name=None):
38+
bookmarkend = self._body.add_bookmarkEnd(name)
39+
return Bookmark(bookmarkend)
3840

39-
# def add_bookmark_end(self, name):
40-
# id = 1
41-
# paragraph = self.add_paragraph()
42-
# return paragraph.add_bookmark_end(id)
41+
def bookmarks(self):
42+
return Bookmarks(self._element.body)
4343

4444
def add_heading(self, text='', level=1):
4545
"""
@@ -227,3 +227,19 @@ def clear_content(self):
227227
"""
228228
self._body.clear_content()
229229
return self
230+
231+
def add_bookmarkStart(self, name):
232+
bookmarkStart = self._body._add_bookmarkStart()
233+
bookmarkStart.name = name
234+
bookmarkStart.bmrk_id = bookmarkStart._next_id
235+
return Bookmark(bookmarkStart)
236+
237+
def add_bookmarkEnd(self, name=None):
238+
239+
bookmarkEnd = self._body._add_bookmarkEnd()
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
245+
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/oxml/document.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ class CT_Document(BaseOxmlElement):
1313
``<w:document>`` element, the root element of a document.xml file.
1414
"""
1515
body = ZeroOrOne('w:body')
16-
bookmarkStart = ZeroOrMore('w:bookmarkStart')
17-
bookmarkEnd = ZeroOrMore('w:bookmarkEnd')
16+
1817
@property
1918
def sectPr_lst(self):
2019
"""
@@ -31,10 +30,10 @@ class CT_Body(BaseOxmlElement):
3130
"""
3231
p = ZeroOrMore('w:p', successors=('w:sectPr',))
3332
tbl = ZeroOrMore('w:tbl', successors=('w:sectPr',))
33+
bookmarkStart = ZeroOrMore('w:bookmarkStart', successors=('w:sectPr',))
34+
bookmarkEnd = ZeroOrMore('w:bookmarkEnd', successors=('w:sectPr',))
3435
sectPr = ZeroOrOne('w:sectPr', successors=())
35-
bookmarkStart = ZeroOrMore('w:bookmarkStart')
36-
bookmarkEnd = ZeroOrMore('w:bookmarkEnd')
37-
36+
3837
def add_section_break(self):
3938
"""
4039
Return the current ``<w:sectPr>`` element after adding a clone of it

docx/oxml/text/paragraph.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ class CT_P(BaseOxmlElement):
1515
"""
1616
pPr = ZeroOrOne('w:pPr')
1717
r = ZeroOrMore('w:r')
18-
bookmarkStart = ZeroOrMore('w:bookmarkStart')
19-
bookmarkEnd = ZeroOrMore('w:bookmarkEnd')
18+
bookmarkStart = ZeroOrMore('w:bookmarkStart', successors=('w:sectPr',))
19+
bookmarkEnd = ZeroOrMore('w:bookmarkEnd', successors=('w:sectPr',))
2020

2121
def _insert_pPr(self, pPr):
2222
self.insert(0, pPr)

docx/oxml/text/run.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class CT_R(BaseOxmlElement):
2929
cr = ZeroOrMore('w:cr')
3030
tab = ZeroOrMore('w:tab')
3131
drawing = ZeroOrMore('w:drawing')
32-
bookmarkStart = ZeroOrMore('w:bookmarkStart')
33-
bookmarkEnd = ZeroOrMore('w:bookmarkEnd')
32+
bookmarkStart = ZeroOrMore('w:bookmarkStart', successors=('w:sectPr',))
33+
bookmarkEnd = ZeroOrMore('w:bookmarkEnd', successors=('w:sectPr',))
3434

3535
def _insert_rPr(self, rPr):
3636
self.insert(0, rPr)

docx/text/bookmarks.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,26 +35,27 @@ def get(self, name, default=None):
3535
return Bookmark(bookmarkStart)
3636
return default
3737

38-
def add_bookmark(self):
39-
return Bookmark(self._element)
40-
4138
@property
4239
def _bookmarkStarts(self):
4340
return self._document.xpath('.//w:bookmarkStart')
4441

42+
@property
43+
def _bookmarkEnds(self):
44+
return self._document.xpath('.//w:bookmarkEnd')
45+
46+
@property
47+
def _next_id(self):
48+
return str(len(self._bookmarkStarts))
4549

4650
class Bookmark(ElementProxy):
4751
def __init__(self, doc_element):
4852
super(Bookmark, self).__init__(doc_element)
4953
self._element = doc_element
5054

51-
def add_bookmark_start(self, id, name):
52-
bmrk = self._element._add_bookmarkStart()
53-
bmrk.name = name
54-
bmrk.bmrk_id = str(id)
55-
return self._element.append(bmrk)
55+
@property
56+
def _id(self):
57+
return self._element.bmrk_id
5658

57-
def add_bookmark_end(self, id):
58-
bmrk = self._element._add_bookmarkEnd()
59-
bmrk.bmrk_id = str(1)
60-
return self._element.append(bmrk)
59+
@property
60+
def _name(self):
61+
return self._element.name

0 commit comments

Comments
 (0)