aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2018-01-16 22:21:21 +0000
committerMichael Williamson <mike@zwobble.org>2018-01-16 22:21:21 +0000
commitcc1b5b19480befc5611a469424a5ae16f9ebce21 (patch)
tree4774f2cbbae87b2b723902d7154b171c2060db78
parent062eb4ff3fea9c49cfce841327d01ddd0099264e (diff)
Read types of relationships
-rw-r--r--lib/docx/body-reader.js8
-rw-r--r--lib/docx/docx-reader.js2
-rw-r--r--lib/docx/relationships-reader.js37
-rw-r--r--test/docx/body-reader.tests.js53
-rw-r--r--test/docx/relationships-reader.tests.js65
5 files changed, 138 insertions, 27 deletions
diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js
index 5958efe..5264d55 100644
--- a/lib/docx/body-reader.js
+++ b/lib/docx/body-reader.js
@@ -236,7 +236,7 @@ function BodyReader(options) {
}
if (relationshipId) {
- var href = relationships[relationshipId].target;
+ var href = relationships.findTargetByRelationshipId(relationshipId);
if (anchor) {
href = uris.replaceFragment(href, anchor);
}
@@ -427,11 +427,11 @@ function BodyReader(options) {
function findBlipImageFile(blip) {
var embedRelationshipId = blip.attributes["r:embed"];
- var linkRelationshipid = blip.attributes["r:link"];
+ var linkRelationshipId = blip.attributes["r:link"];
if (embedRelationshipId) {
return findEmbeddedImageFile(embedRelationshipId);
} else {
- var imagePath = relationships[linkRelationshipid].target;
+ var imagePath = relationships.findTargetByRelationshipId(linkRelationshipId);
return {
path: imagePath,
read: files.read.bind(files, imagePath)
@@ -452,7 +452,7 @@ function BodyReader(options) {
}
function findEmbeddedImageFile(relationshipId) {
- var path = uris.uriToZipEntryName("word", relationships[relationshipId].target);
+ var path = uris.uriToZipEntryName("word", relationships.findTargetByRelationshipId(relationshipId));
return {
path: path,
read: docxFile.read.bind(docxFile, path)
diff --git a/lib/docx/docx-reader.js b/lib/docx/docx-reader.js
index db15b95..54f2a3b 100644
--- a/lib/docx/docx-reader.js
+++ b/lib/docx/docx-reader.js
@@ -91,7 +91,7 @@ function readXmlFileWithBody(filename, options, func) {
var readRelationshipsFromZipFile = xmlFileReader({
filename: relationshipsFilename(filename),
readElement: relationshipsReader.readRelationships,
- defaultValue: {}
+ defaultValue: relationshipsReader.defaultValue
});
return readRelationshipsFromZipFile(options.docxFile).then(function(relationships) {
diff --git a/lib/docx/relationships-reader.js b/lib/docx/relationships-reader.js
index 93fc618..4db172e 100644
--- a/lib/docx/relationships-reader.js
+++ b/lib/docx/relationships-reader.js
@@ -1,14 +1,43 @@
exports.readRelationships = readRelationships;
+exports.defaultValue = new Relationships([]);
+exports.Relationships = Relationships;
function readRelationships(element) {
- var relationships = {};
+ var relationships = [];
element.children.forEach(function(child) {
if (child.name === "{http://schemas.openxmlformats.org/package/2006/relationships}Relationship") {
- relationships[child.attributes.Id] = {
- target: child.attributes.Target
+ var relationship = {
+ relationshipId: child.attributes.Id,
+ target: child.attributes.Target,
+ type: child.attributes.Type
};
+ relationships.push(relationship);
}
});
- return relationships;
+ return new Relationships(relationships);
+}
+
+function Relationships(relationships) {
+ var targetsByRelationshipId = {};
+ relationships.forEach(function(relationship) {
+ targetsByRelationshipId[relationship.relationshipId] = relationship.target;
+ });
+
+ var targetsByType = {};
+ relationships.forEach(function(relationship) {
+ if (!targetsByType[relationship.type]) {
+ targetsByType[relationship.type] = [];
+ }
+ targetsByType[relationship.type].push(relationship.target);
+ });
+
+ return {
+ findTargetByRelationshipId: function(relationshipId) {
+ return targetsByRelationshipId[relationshipId];
+ },
+ findTargetsByType: function(type) {
+ return targetsByType[type] || [];
+ }
+ };
}
diff --git a/test/docx/body-reader.tests.js b/test/docx/body-reader.tests.js
index 039a9db..ceeb9c1 100644
--- a/test/docx/body-reader.tests.js
+++ b/test/docx/body-reader.tests.js
@@ -25,6 +25,7 @@ var documents = require("../../lib/documents");
var xml = require("../../lib/xml");
var XmlElement = xml.Element;
var Numbering = require("../../lib/docx/numbering-xml").Numbering;
+var Relationships = require("../../lib/docx/relationships-reader").Relationships;
var Styles = require("../../lib/docx/styles-reader").Styles;
var warning = require("../../lib/results").warning;
@@ -810,9 +811,9 @@ function isImage(options) {
function readEmbeddedImage(element) {
return readXmlElement(element, {
- relationships: {
- "rId5": {target: "media/hat.png"}
- },
+ relationships: new Relationships([
+ imageRelationship("rId5", "media/hat.png")
+ ]),
contentTypes: fakeContentTypes,
docxFile: createFakeDocxFile({
"word/media/hat.png": IMAGE_BUFFER
@@ -932,9 +933,9 @@ test("can read linked pictures", function() {
});
var element = single(readXmlElementValue(drawing, {
- relationships: {
- "rId5": {target: "file:///media/hat.png"}
- },
+ relationships: new Relationships([
+ imageRelationship("rId5", "file:///media/hat.png")
+ ]),
contentTypes: fakeContentTypes,
files: testing.createFakeFiles({
"file:///media/hat.png": IMAGE_BUFFER
@@ -954,9 +955,9 @@ test("warning if unsupported image type", function() {
});
var result = readXmlElement(drawing, {
- relationships: {
- "rId5": {target: "media/hat.emf"}
- },
+ relationships: new Relationships([
+ imageRelationship("rId5", "media/hat.emf")
+ ]),
contentTypes: fakeContentTypes,
docxFile: createFakeDocxFile({
"word/media/hat.emf": IMAGE_BUFFER
@@ -1009,9 +1010,9 @@ test("w:hyperlink", {
"is read as external hyperlink if it has a relationship ID": function() {
var runXml = new XmlElement("w:r", {}, []);
var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42"}, [runXml]);
- var relationships = {
- "r42": {target: "http://example.com"}
- };
+ var relationships = new Relationships([
+ hyperlinkRelationship("r42", "http://example.com")
+ ]);
var result = readXmlElement(hyperlinkXml, {relationships: relationships});
assert.deepEqual(result.value.href, "http://example.com");
assert.deepEqual(result.value.children[0].type, "run");
@@ -1020,9 +1021,9 @@ test("w:hyperlink", {
"is read as external hyperlink if it has a relationship ID and an anchor": function() {
var runXml = new XmlElement("w:r", {}, []);
var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42", "w:anchor": "fragment"}, [runXml]);
- var relationships = {
- "r42": {target: "http://example.com/"}
- };
+ var relationships = new Relationships([
+ hyperlinkRelationship("r42", "http://example.com/")
+ ]);
var result = readXmlElement(hyperlinkXml, {relationships: relationships});
assert.deepEqual(result.value.href, "http://example.com/#fragment");
assert.deepEqual(result.value.children[0].type, "run");
@@ -1031,9 +1032,9 @@ test("w:hyperlink", {
"existing fragment is replaced when anchor is set on external link": function() {
var runXml = new XmlElement("w:r", {}, []);
var hyperlinkXml = new XmlElement("w:hyperlink", {"r:id": "r42", "w:anchor": "fragment"}, [runXml]);
- var relationships = {
- "r42": {target: "http://example.com/#previous"}
- };
+ var relationships = new Relationships([
+ hyperlinkRelationship("r42", "http://example.com/#previous")
+ ]);
var result = readXmlElement(hyperlinkXml, {relationships: relationships});
assert.deepEqual(result.value.href, "http://example.com/#fragment");
assert.deepEqual(result.value.children[0].type, "run");
@@ -1251,3 +1252,19 @@ function assertImageBuffer(element, expectedImageBuffer) {
assert.equal(readValue, expectedImageBuffer);
});
}
+
+function hyperlinkRelationship(relationshipId, target) {
+ return {
+ relationshipId: relationshipId,
+ target: target,
+ type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
+ };
+}
+
+function imageRelationship(relationshipId, target) {
+ return {
+ relationshipId: relationshipId,
+ target: target,
+ type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
+ };
+}
diff --git a/test/docx/relationships-reader.tests.js b/test/docx/relationships-reader.tests.js
new file mode 100644
index 0000000..60db3b4
--- /dev/null
+++ b/test/docx/relationships-reader.tests.js
@@ -0,0 +1,65 @@
+var assert = require("assert");
+
+var readRelationships = require("../../lib/docx/relationships-reader").readRelationships;
+var xml = require("../../lib/xml");
+var test = require("../test")(module);
+
+
+test("relationships can be found by ID", function() {
+ var relationships = readRelationships(relationshipsElement([
+ relationshipElement({
+ "Id": "rId1",
+ "Target": "http://example.com/",
+ "Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
+ }),
+ relationshipElement({
+ "Id": "rId2",
+ "Target": "http://example.net/",
+ "Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
+ })
+ ]));
+ assert.equal(relationships.findTargetByRelationshipId("rId1"), "http://example.com/");
+});
+
+
+test("relationships can be found by type", function() {
+ var relationships = readRelationships(relationshipsElement([
+ relationshipElement({
+ "Id": "rId2",
+ "Target": "docProps/core.xml",
+ "Type": "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"
+ }),
+ relationshipElement({
+ "Id": "rId1",
+ "Target": "word/document.xml",
+ "Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
+ }),
+ relationshipElement({
+ "Id": "rId3",
+ "Target": "word/document2.xml",
+ "Type": "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
+ })
+ ]));
+ assert.deepEqual(
+ relationships.findTargetsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"),
+ ["word/document.xml", "word/document2.xml"]
+ );
+});
+
+
+test("when there are no relationships of requested type then empty array is returned", function() {
+ var relationships = readRelationships(relationshipsElement([]));
+ assert.deepEqual(
+ relationships.findTargetsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"),
+ []
+ );
+});
+
+
+function relationshipsElement(children) {
+ return xml.element("{http://schemas.openxmlformats.org/package/2006/relationships}Relationships", {}, children)
+}
+
+function relationshipElement(attributes) {
+ return xml.element("{http://schemas.openxmlformats.org/package/2006/relationships}Relationship", attributes, [])
+}