diff options
| author | Michael Williamson <mike@zwobble.org> | 2013-12-01 01:06:03 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2013-12-01 01:06:03 +0000 |
| commit | f9148d6f5dcf1e8188411c800daeb0ab493be19b (patch) | |
| tree | a8fddd8f839b5519f93979d9533eeb60d336e0fc | |
| parent | 1ca475c19254ebb8e3c453bab8599c19305e45a5 (diff) | |
Add basic docx file reading
| -rw-r--r-- | mammoth/docx.py | 78 | ||||
| -rw-r--r-- | tests/docx_tests.py | 79 |
2 files changed, 157 insertions, 0 deletions
diff --git a/mammoth/docx.py b/mammoth/docx.py new file mode 100644 index 0000000..9a3fe36 --- /dev/null +++ b/mammoth/docx.py @@ -0,0 +1,78 @@ +import zipfile + +from . import documents +from .results import Result +from .xmlparser import parse_xml, node_types + + +_namespaces = [ + ("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main"), +] + + +def read(fileobj): + zip_file = zipfile.ZipFile(fileobj) + document_fileobj = zip_file.open("word/document.xml") + document_xml = parse_xml(document_fileobj, _namespaces) + return Result(read_xml_element(document_xml), []) + + +_handlers = {} + + +def handler(name): + def add(func): + _handlers[name] = func + + return add + + +def read_xml_element(element): + handler = _handlers.get(element.name) + if handler is None: + return None + else: + return handler(element) + + +@handler("w:t") +def text(element): + return documents.Text(_inner_text(element)) + + +@handler("w:r") +def run(element): + return documents.Run(_read_xml_elements(element.children)) + + +@handler("w:p") +def paragraph(element): + return documents.Paragraph(_read_xml_elements(element.children)) + + +@handler("w:body") +def paragraph(element): + return _read_xml_elements(element.children) + + +@handler("w:document") +def paragraph(element): + body_element = _find(lambda child: child.name == "w:body", element.children) + return documents.Document(_read_xml_elements(body_element.children)) + + +def _find(predicate, iterable): + for item in iterable: + if predicate(item): + return item + + +def _read_xml_elements(elements): + return filter(None, map(read_xml_element, elements)) + + +def _inner_text(node): + if node.node_type == node_types.text: + return node.value + else: + return "".join(_inner_text(child) for child in node.children) diff --git a/tests/docx_tests.py b/tests/docx_tests.py new file mode 100644 index 0000000..55a2222 --- /dev/null +++ b/tests/docx_tests.py @@ -0,0 +1,79 @@ +from nose.tools import istest, assert_equal + +from mammoth import docx, documents +from mammoth.xmlparser import element as xml_element, text as xml_text +from .testing import test_path + +@istest +class ReadTests(object): + @istest + def can_read_document_with_single_paragraph_with_single_run_of_text(self): + with open(test_path("single-paragraph.docx")) as fileobj: + result = docx.read(fileobj=fileobj) + expected_document = documents.Document([ + documents.Paragraph([ + documents.Run([ + documents.Text("Walking on imported air") + ]) + ]) + ]) + assert_equal(expected_document, result.value) + + +@istest +class ReadXmlElementTests(object): + @istest + def text_from_text_element_is_read(self): + element = _text_element("Hello!") + assert_equal(documents.Text("Hello!"), docx.read_xml_element(element)) + + @istest + def can_read_text_within_run(self): + element = _run_element_with_text("Hello!") + assert_equal( + documents.Run([documents.Text("Hello!")]), + docx.read_xml_element(element) + ) + + @istest + def can_read_text_within_paragraph(self): + element = _paragraph_element_with_text("Hello!") + assert_equal( + documents.Paragraph([documents.Run([documents.Text("Hello!")])]), + docx.read_xml_element(element) + ) + + @istest + def can_read_text_within_paragraph(self): + element = _paragraph_element_with_text("Hello!") + assert_equal( + documents.Paragraph([documents.Run([documents.Text("Hello!")])]), + docx.read_xml_element(element) + ) + + @istest + def can_read_text_within_document(self): + element = _document_element_with_text("Hello!") + assert_equal( + documents.Document([documents.Paragraph([documents.Run([documents.Text("Hello!")])])]), + docx.read_xml_element(element) + ) + + +def _document_element_with_text(text): + return xml_element("w:document", {}, [ + xml_element("w:body", {}, [_paragraph_element_with_text(text)]) + ]) + + +def _paragraph_element_with_text(text): + return xml_element("w:p", {}, [_run_element_with_text(text)]) + + +def _run_element_with_text(text): + return xml_element("w:r", {}, [_text_element(text)]) + + +def _text_element(value): + return xml_element("w:t", {}, [xml_text(value)]) + |
