aboutsummaryrefslogtreecommitdiff
path: root/mammoth
diff options
context:
space:
mode:
authorBruno Herfst <hello@brunoherfst.com>2016-10-26 11:04:09 +1100
committerMichael Williamson <mike@zwobble.org>2016-12-10 23:07:48 +0000
commitbc8c341b37bfac34bbeaccdd5368c2d7edc309ac (patch)
tree5c18d634763f5f6ae0defeb07368f0ae28d8ef4d /mammoth
parent8661cad2a82b66254fff564f4a514cbd67ad371d (diff)
Add support for page and column breaks
Diffstat (limited to 'mammoth')
-rw-r--r--mammoth/conversion.py30
-rw-r--r--mammoth/document_matchers.py10
-rw-r--r--mammoth/documents.py11
-rw-r--r--mammoth/docx/body_xml.py19
-rw-r--r--mammoth/styles/parser/document_matcher_parser.py20
5 files changed, 73 insertions, 17 deletions
diff --git a/mammoth/conversion.py b/mammoth/conversion.py
index 9398c5c..bae503a 100644
--- a/mammoth/conversion.py
+++ b/mammoth/conversion.py
@@ -132,6 +132,7 @@ class _DocumentConverter(documents.ElementVisitor):
else:
return html_paths.empty
+
def visit_text(self, text):
return [html.text(text.value)]
@@ -176,11 +177,22 @@ class _DocumentConverter(documents.ElementVisitor):
return [
html.element("td", attributes, nodes)
]
-
-
- def visit_line_break(self, line_break):
- return [html.element("br")]
-
+
+
+ def visit_break(self, break_):
+ return self._find_html_path_for_break(break_).wrap(lambda: [])
+
+
+ def _find_html_path_for_break(self, break_):
+ style = self._find_style(break_, "break")
+ if style is not None:
+ return style.html_path
+ elif break_.break_type == "line":
+ return html_paths.path([html_paths.element("br", fresh=True)])
+ else:
+ return html_paths.empty
+
+
def visit_note_reference(self, note_reference):
self._note_references.append(note_reference)
note_number = len(self._note_references)
@@ -192,6 +204,7 @@ class _DocumentConverter(documents.ElementVisitor):
}, [html.text("[{0}]".format(note_number))])
])
]
+
def visit_note(self, note):
note_body = self._visit_all(note.body) + [
@@ -300,7 +313,12 @@ class _DocumentConverter(documents.ElementVisitor):
def _document_matcher_matches(matcher, element, element_type):
if matcher.element_type in ["underline", "strikethrough", "bold", "italic", "comment_reference"]:
return matcher.element_type == element_type
- else:
+ elif matcher.element_type == "break":
+ return (
+ matcher.element_type == element_type and
+ matcher.break_type == element.break_type
+ )
+ else: # matcher.element_type in ["paragraph", "run"]:
return (
matcher.element_type == element_type and (
matcher.style_id is None or
diff --git a/mammoth/document_matchers.py b/mammoth/document_matchers.py
index d1f8e74..faccb50 100644
--- a/mammoth/document_matchers.py
+++ b/mammoth/document_matchers.py
@@ -39,6 +39,15 @@ class comment_reference(object):
element_type = "comment_reference"
+BreakMatcher = collections.namedtuple("BreakMatcher", ["break_type"])
+BreakMatcher.element_type = "break"
+
+
+line_break = BreakMatcher("line")
+page_break = BreakMatcher("page")
+column_break = BreakMatcher("column")
+
+
def equal_to(value):
return StringMatcher(_operator_equal_to, value)
@@ -50,7 +59,6 @@ def _operator_equal_to(first, second):
def starts_with(value):
return StringMatcher(_operator_starts_with, value)
-
def _operator_starts_with(first, second):
return second.upper().startswith(first.upper())
diff --git a/mammoth/documents.py b/mammoth/documents.py
index 2767f86..327380d 100644
--- a/mammoth/documents.py
+++ b/mammoth/documents.py
@@ -53,8 +53,13 @@ class TableCell(HasChildren):
rowspan = cobble.field()
@cobble.data
-class LineBreak(Element):
- pass
+class Break(Element):
+ break_type = cobble.field()
+
+line_break = Break("line")
+page_break = Break("page")
+column_break = Break("column")
+
@cobble.data
class Tab(Element):
@@ -123,8 +128,6 @@ def table_cell(children, colspan=None, rowspan=None):
return TableCell(children=children, colspan=colspan, rowspan=rowspan)
-line_break = LineBreak
-
def numbering_level(level_index, is_ordered):
return _NumberingLevel(str(level_index), bool(is_ordered))
diff --git a/mammoth/docx/body_xml.py b/mammoth/docx/body_xml.py
index 22d8440..1fcd567 100644
--- a/mammoth/docx/body_xml.py
+++ b/mammoth/docx/body_xml.py
@@ -253,7 +253,8 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f
return children_result.map(lambda children: documents.hyperlink(anchor=anchor, children=children))
else:
return children_result
-
+
+
def bookmark_start(element):
name = element.attributes.get("w:name")
if name == "_GoBack":
@@ -262,13 +263,19 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f
return _success(documents.bookmark(name))
- def br(element):
+ def break_(element):
break_type = element.attributes.get("w:type")
- if break_type:
+
+ if not break_type or break_type == "textWrapping":
+ return _success(documents.line_break)
+ elif break_type == "page":
+ return _success(documents.page_break)
+ elif break_type == "column":
+ return _success(documents.column_break)
+ else:
warning = results.warning("Unsupported break type: {0}".format(break_type))
return _empty_result_with_message(warning)
- else:
- return _success(documents.line_break())
+
def inline(element):
properties = element.find_child_or_null("wp:docPr").attributes
@@ -372,7 +379,7 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f
"w:pict": pict,
"w:hyperlink": hyperlink,
"w:bookmarkStart": bookmark_start,
- "w:br": br,
+ "w:br": break_,
"wp:inline": inline,
"wp:anchor": inline,
"v:imagedata": read_imagedata,
diff --git a/mammoth/styles/parser/document_matcher_parser.py b/mammoth/styles/parser/document_matcher_parser.py
index 7f117b7..36999d0 100644
--- a/mammoth/styles/parser/document_matcher_parser.py
+++ b/mammoth/styles/parser/document_matcher_parser.py
@@ -40,6 +40,9 @@ def parse_document_matcher(tokens):
elif tokens.try_skip(TokenType.IDENTIFIER, "comment-reference"):
return document_matchers.comment_reference
+ elif tokens.try_skip(TokenType.IDENTIFIER, "br"):
+ return _parse_break(tokens)
+
else:
raise LineParseError("Unrecognised document element: {0}".format(tokens.next_value(TokenType.IDENTIFIER)))
@@ -78,3 +81,20 @@ def _parse_list_type(tokens):
return False
else:
raise LineParseError("Unrecognised list type: {0}".format(list_type))
+
+
+def _parse_break(tokens):
+ tokens.skip(TokenType.SYMBOL, "[")
+ tokens.skip(TokenType.IDENTIFIER, "type")
+ tokens.skip(TokenType.SYMBOL, "=")
+ type_name = parse_string(tokens)
+ tokens.skip(TokenType.SYMBOL, "]");
+
+ if type_name == "line":
+ return document_matchers.line_break
+ elif type_name == "page":
+ return document_matchers.page_break
+ elif type_name == "column":
+ return document_matchers.column_break
+ else:
+ raise LineParseError("Unrecognised break type: {0}".format(type_name))