aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2018-01-19 19:52:53 +0000
committerMichael Williamson <mike@zwobble.org>2018-01-19 19:52:53 +0000
commitdcca2c6ffe71e399caeeac6c2d44070c097a9cc5 (patch)
tree1a40291eb0a62d61616645fbc2ea251d9c9e12d3
parent882f1aff778b56bbc15222baa0555616f8e102ac (diff)
Read relationship types
-rw-r--r--mammoth/docx/relationships_xml.py26
-rw-r--r--tests/docx/body_xml_tests.py52
-rw-r--r--tests/docx/relationships_xml_tests.py45
3 files changed, 96 insertions, 27 deletions
diff --git a/mammoth/docx/relationships_xml.py b/mammoth/docx/relationships_xml.py
index 8bf3a89..c30c428 100644
--- a/mammoth/docx/relationships_xml.py
+++ b/mammoth/docx/relationships_xml.py
@@ -3,21 +3,33 @@ import collections
class Relationships(object):
def __init__(self, relationships):
- self._relationships = relationships
+ self._targets_by_id = dict(
+ (relationship.relationship_id, relationship.target)
+ for relationship in relationships
+ )
+ self._targets_by_type = collections.defaultdict(list)
+ for relationship in relationships:
+ self._targets_by_type[relationship.type].append(relationship.target)
def find_target_by_relationship_id(self, key):
- return self._relationships[key].target
+ return self._targets_by_id[key]
+
+ def find_targets_by_type(self, relationship_type):
+ return self._targets_by_type[relationship_type]
-Relationship = collections.namedtuple("Relationship", ["target"])
+Relationship = collections.namedtuple("Relationship", ["relationship_id", "target", "type"])
def read_relationships_xml_element(element):
children = element.find_children("relationships:Relationship")
- return Relationships(dict(map(_read_relationship, children)))
+ return Relationships(list(map(_read_relationship, children)))
def _read_relationship(element):
- relationship_id = element.attributes["Id"]
- relationship = Relationship(target=element.attributes["Target"])
- return relationship_id, relationship
+ relationship = Relationship(
+ relationship_id=element.attributes["Id"],
+ target=element.attributes["Target"],
+ type=element.attributes["Type"],
+ )
+ return relationship
diff --git a/tests/docx/body_xml_tests.py b/tests/docx/body_xml_tests.py
index 067037e..537f123 100644
--- a/tests/docx/body_xml_tests.py
+++ b/tests/docx/body_xml_tests.py
@@ -738,9 +738,9 @@ def _assert_children_are_converted_normally(tag_name):
class HyperlinkTests(object):
@istest
def hyperlink_is_read_as_external_hyperlink_if_it_has_a_relationship_id(self):
- relationships = Relationships({
- "r42": Relationship(target="http://example.com")
- })
+ relationships = Relationships([
+ _hyperlink_relationship("r42", "http://example.com"),
+ ])
run_element = xml_element("w:r")
element = xml_element("w:hyperlink", {"r:id": "r42"}, [run_element])
assert_equal(
@@ -750,9 +750,9 @@ class HyperlinkTests(object):
@istest
def hyperlink_is_read_as_external_hyperlink_if_it_has_a_relationship_id_and_an_anchor(self):
- relationships = Relationships({
- "r42": Relationship(target="http://example.com/")
- })
+ relationships = Relationships([
+ _hyperlink_relationship("r42", "http://example.com/"),
+ ])
run_element = xml_element("w:r")
element = xml_element("w:hyperlink", {"r:id": "r42", "w:anchor": "fragment"}, [run_element])
assert_equal(
@@ -762,9 +762,9 @@ class HyperlinkTests(object):
@istest
def existing_fragment_is_replaced_when_anchor_is_set_on_external_link(self):
- relationships = Relationships({
- "r42": Relationship(target="http://example.com/#previous")
- })
+ relationships = Relationships([
+ _hyperlink_relationship("r42", "http://example.com/#previous"),
+ ])
run_element = xml_element("w:r")
element = xml_element("w:hyperlink", {"r:id": "r42", "w:anchor": "fragment"}, [run_element])
assert_equal(
@@ -870,9 +870,9 @@ class ImageTests(object):
IMAGE_RELATIONSHIP_ID = "rId5"
def _read_embedded_image(self, element):
- relationships = Relationships({
- self.IMAGE_RELATIONSHIP_ID: Relationship(target="media/hat.png")
- })
+ relationships = Relationships([
+ _image_relationship(self.IMAGE_RELATIONSHIP_ID, "media/hat.png"),
+ ])
mocks = funk.Mocks()
docx_file = mocks.mock()
@@ -1002,9 +1002,9 @@ class ImageTests(object):
description="It's a hat",
)
- relationships = Relationships({
- "rId5": Relationship(target="media/hat.emf")
- })
+ relationships = Relationships([
+ _image_relationship("rId5", "media/hat.emf"),
+ ])
docx_file = mocks.mock()
funk.allows(docx_file).open("word/media/hat.emf").returns(io.BytesIO(self.IMAGE_BYTES))
@@ -1031,9 +1031,9 @@ class ImageTests(object):
description="It's a hat",
)
- relationships = Relationships({
- "rId5": Relationship(target="file:///media/hat.png")
- })
+ relationships = Relationships([
+ _image_relationship("rId5", "file:///media/hat.png"),
+ ])
files = mocks.mock()
funk.allows(files).verify("file:///media/hat.png")
@@ -1276,3 +1276,19 @@ def single(values):
return values[0]
else:
raise Exception("Had {0} elements".format(len(values)))
+
+
+def _hyperlink_relationship(relationship_id, target):
+ return Relationship(
+ relationship_id=relationship_id,
+ target=target,
+ type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
+ )
+
+
+def _image_relationship(relationship_id, target):
+ return Relationship(
+ relationship_id=relationship_id,
+ target=target,
+ type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ )
diff --git a/tests/docx/relationships_xml_tests.py b/tests/docx/relationships_xml_tests.py
index c3d0af0..5e52142 100644
--- a/tests/docx/relationships_xml_tests.py
+++ b/tests/docx/relationships_xml_tests.py
@@ -5,16 +5,57 @@ from mammoth.docx.relationships_xml import read_relationships_xml_element
@istest
-def target_is_read_from_relationship_element():
+def relationship_targets_can_be_found_by_id():
element = xml_element("relationships:Relationships", {}, [
xml_element("relationships:Relationship", {
"Id": "rId8",
"Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
"Target": "http://example.com",
- })
+ }),
+ xml_element("relationships:Relationship", {
+ "Id": "rId2",
+ "Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
+ "Target": "http://example.net",
+ }),
])
relationships = read_relationships_xml_element(element)
assert_equal(
"http://example.com",
relationships.find_target_by_relationship_id("rId8"),
)
+
+
+@istest
+def relationship_targets_can_be_found_by_type():
+ element = xml_element("relationships:Relationships", {}, [
+ xml_element("relationships:Relationship", {
+ "Id": "rId2",
+ "Target": "docProps/core.xml",
+ "Type": "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
+ }),
+ xml_element("relationships:Relationship", {
+ "Id": "rId1",
+ "Target": "word/document.xml",
+ "Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
+ }),
+ xml_element("relationships:Relationship", {
+ "Id": "rId3",
+ "Target": "word/document2.xml",
+ "Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
+ }),
+ ])
+ relationships = read_relationships_xml_element(element)
+ assert_equal(
+ ["word/document.xml", "word/document2.xml"],
+ relationships.find_targets_by_type("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"),
+ )
+
+
+@istest
+def when_there_are_no_relationships_of_requested_type_then_empty_list_is_returned():
+ element = xml_element("relationships:Relationships", {}, [])
+ relationships = read_relationships_xml_element(element)
+ assert_equal(
+ [],
+ relationships.find_targets_by_type("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"),
+ )