summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2019-03-17 21:27:34 +0000
committerMichael Williamson <mike@zwobble.org>2019-03-17 21:28:06 +0000
commita45ad007f9c3e366313b0dc8d5b2b31eb43912d0 (patch)
treead78299162e299dc3a4688f730a2a123e384c4f2
parent65834fa39ee1ea77ef5581bc11e4e6046c6499a6 (diff)
Follow w:numStyleLink in w:abstractNum
-rw-r--r--NEWS4
-rw-r--r--mammoth/docx/__init__.py2
-rw-r--r--mammoth/docx/numbering_xml.py19
-rw-r--r--tests/docx/numbering_xml_tests.py26
4 files changed, 45 insertions, 6 deletions
diff --git a/NEWS b/NEWS
index 31aeb23..8f23524 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+# 1.4.9
+
+* Improve list support by following w:numStyleLink in w:abstractNum.
+
# 1.4.8
* Preserve empty table rows.
diff --git a/mammoth/docx/__init__.py b/mammoth/docx/__init__.py
index 63a634c..fcb5da5 100644
--- a/mammoth/docx/__init__.py
+++ b/mammoth/docx/__init__.py
@@ -153,7 +153,7 @@ def _part_with_body_reader(document_path, zip_file, part_paths):
zip_file,
part_paths.numbering,
lambda element: read_numbering_xml_element(element, styles=styles),
- default=Numbering(abstract_nums={}, nums={}),
+ default=Numbering.EMPTY,
)
def read_part(name, reader, default=_undefined):
diff --git a/mammoth/docx/numbering_xml.py b/mammoth/docx/numbering_xml.py
index 3a0645e..af3d1d5 100644
--- a/mammoth/docx/numbering_xml.py
+++ b/mammoth/docx/numbering_xml.py
@@ -1,12 +1,13 @@
import cobble
from ..documents import numbering_level
+from .styles_xml import Styles
def read_numbering_xml_element(element, styles):
abstract_nums = _read_abstract_nums(element)
nums = _read_nums(element)
- return Numbering(abstract_nums=abstract_nums, nums=nums)
+ return Numbering(abstract_nums=abstract_nums, nums=nums, styles=styles)
def _read_abstract_nums(element):
@@ -17,12 +18,14 @@ def _read_abstract_nums(element):
def _read_abstract_num(element):
abstract_num_id = element.attributes.get("w:abstractNumId")
levels = _read_abstract_num_levels(element)
- return abstract_num_id, _AbstractNum(levels=levels)
+ num_style_link = element.find_child_or_null("w:numStyleLink").attributes.get("w:val")
+ return abstract_num_id, _AbstractNum(levels=levels, num_style_link=num_style_link)
@cobble.data
class _AbstractNum(object):
levels = cobble.field()
+ num_style_link = cobble.field()
def _read_abstract_num_levels(element):
@@ -60,9 +63,10 @@ class _Num(object):
class Numbering(object):
- def __init__(self, abstract_nums, nums):
+ def __init__(self, abstract_nums, nums, styles):
self._abstract_nums = abstract_nums
self._nums = nums
+ self._styles = styles
def find_level(self, num_id, level):
num = self._nums.get(num_id)
@@ -70,4 +74,11 @@ class Numbering(object):
return None
else:
abstract_num = self._abstract_nums[num.abstract_num_id]
- return abstract_num.levels.get(level)
+ if abstract_num.num_style_link is None:
+ return abstract_num.levels.get(level)
+ else:
+ style = self._styles.find_numbering_style_by_id(abstract_num.num_style_link)
+ return self.find_level(style.num_id, level)
+
+
+Numbering.EMPTY = Numbering(abstract_nums={}, nums={}, styles=Styles.EMPTY)
diff --git a/tests/docx/numbering_xml_tests.py b/tests/docx/numbering_xml_tests.py
index 467d406..b707ba1 100644
--- a/tests/docx/numbering_xml_tests.py
+++ b/tests/docx/numbering_xml_tests.py
@@ -2,7 +2,7 @@ from nose.tools import istest, assert_equal
from mammoth.docx.xmlparser import element as xml_element
from mammoth.docx.numbering_xml import read_numbering_xml_element
-from mammoth.docx.styles_xml import Styles
+from mammoth.docx.styles_xml import NumberingStyle, Styles
@istest
@@ -50,6 +50,30 @@ def find_level_returns_none_if_level_cannot_be_found():
assert_equal(None, numbering.find_level("47", "2"))
+@istest
+def when_abstract_num_has_num_style_link_then_style_is_used_to_find_num():
+ numbering = _read_numbering_xml_element(
+ xml_element("w:numbering", {}, [
+ xml_element("w:abstractNum", {"w:abstractNumId": "100"}, [
+ xml_element("w:lvl", {"w:ilvl": "0"}, [
+ xml_element("w:numFmt", {"w:val": "decimal"}),
+ ]),
+ ]),
+ xml_element("w:abstractNum", {"w:abstractNumId": "101"}, [
+ xml_element("w:numStyleLink", {"w:val": "List1"}),
+ ]),
+ xml_element("w:num", {"w:numId": "200"}, [
+ xml_element("w:abstractNumId", {"w:val": "100"}),
+ ]),
+ xml_element("w:num", {"w:numId": "201"}, [
+ xml_element("w:abstractNumId", {"w:val": "101"}),
+ ])
+ ]),
+ styles=Styles.create(numbering_styles={"List1": NumberingStyle(num_id="200")}),
+ )
+ assert_equal(True, numbering.find_level("201", "0").is_ordered)
+
+
def _read_numbering_xml_element(element, styles=None):
if styles is None:
styles = Styles.EMPTY