diff options
| author | Michael Williamson <mike@zwobble.org> | 2014-06-10 16:23:15 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2014-06-10 16:23:15 +0100 |
| commit | 8aec6e713d08a532194b50591fa338ecb9a251f9 (patch) | |
| tree | 00004b0324527dac50add38cdf6ac39cec604227 | |
| parent | ee2fc5da880df5f9ea8cdaebc506d130c3009ce3 (diff) | |
Basic support for footnotes
| -rw-r--r-- | lib/docx/document-xml-reader.js | 21 | ||||
| -rw-r--r-- | lib/docx/docx-reader.js | 13 | ||||
| -rw-r--r-- | lib/docx/footnotes-reader.js | 12 | ||||
| -rw-r--r-- | lib/results.js | 5 | ||||
| -rw-r--r-- | package.json | 2 | ||||
| -rw-r--r-- | tests/docx/document-xml-reader.tests.js | 23 | ||||
| -rw-r--r-- | tests/docx/footnotes-reader.tests.js | 16 | ||||
| -rw-r--r-- | tests/mammoth.tests.js | 5 |
8 files changed, 67 insertions, 30 deletions
diff --git a/lib/docx/document-xml-reader.js b/lib/docx/document-xml-reader.js index 348bccf..6bf20dc 100644 --- a/lib/docx/document-xml-reader.js +++ b/lib/docx/document-xml-reader.js @@ -14,19 +14,34 @@ function DocumentXmlReader(options) { var docxFile = options.docxFile; var numbering = options.numbering; var styles = options.styles; - var footnotes = options.footnotes; + var rawFootnotes = options.footnotes || []; function convertXmlToDocument(documentXml) { var body = documentXml.root.first("w:body"); var result = readXmlElements(body.children) - .map(function(children) { - return new documents.Document(children, footnotes); + .flatMap(function(children) { + return readFootnotes().map(function(footnotes) { + return new documents.Document(children, {footnotes: footnotes}); + }); }); result.document = result.value; return result; } + + function readFootnotes() { + return Result.combine(rawFootnotes.map(function(rawFootnote) { + return readXmlElements(rawFootnote.body).map(function(body) { + return new documents.Footnote({ + id: rawFootnote.id, + body: body + }); + }); + })).map(function(footnotes) { + return new documents.Footnotes(_.indexBy(footnotes, "id")); + }); + } function readXmlElements(elements) { var results = elements.map(readXmlElement); diff --git a/lib/docx/docx-reader.js b/lib/docx/docx-reader.js index ae09adc..3afafee 100644 --- a/lib/docx/docx-reader.js +++ b/lib/docx/docx-reader.js @@ -10,6 +10,7 @@ var relationshipsReader = require("./relationships-reader"); var contentTypesReader = require("./content-types-reader"); var numberingXml = require("./numbering-xml"); var stylesReader = require("./styles-reader"); +var footnotesReader = require("./footnotes-reader"); function read(options) { @@ -20,14 +21,16 @@ function read(options) { readContentTypesFromZipFile(docxFile), readNumberingFromZipFile(docxFile), readStylesFromZipFile(docxFile), + readFootnotesFromZipFile(docxFile), readXmlFromZipFile(docxFile, "word/document.xml"), - ]).spread(function(relationships, contentTypes, numbering, styles, documentXml) { + ]).spread(function(relationships, contentTypes, numbering, styles, footnotes, documentXml) { var reader = new DocumentXmlReader({ relationships: relationships, contentTypes: contentTypes, docxFile: docxFile, numbering: numbering, - styles: styles + styles: styles, + footnotes: footnotes }); return reader.convertXmlToDocument(documentXml); }); @@ -66,3 +69,9 @@ var readStylesFromZipFile = xmlFileReader({ readElement: stylesReader.readStylesXml, defaultValue: stylesReader.defaultStyles }); + +var readFootnotesFromZipFile = xmlFileReader({ + filename: "word/footnotes.xml", + readElement: footnotesReader.readFootnotesXml, + defaultValue: undefined +}); diff --git a/lib/docx/footnotes-reader.js b/lib/docx/footnotes-reader.js index c7ec98c..a653b8a 100644 --- a/lib/docx/footnotes-reader.js +++ b/lib/docx/footnotes-reader.js @@ -3,17 +3,11 @@ exports.readFootnotesXml = readFootnotesXml; var Footnotes = require("../documents").Footnotes; function readFootnotesXml(xml) { - var footnotes = {}; - - xml.root.getElementsByTagName("w:footnote").forEach(function(footnoteElement) { - var id = footnoteElement.attributes["w:id"]; - footnotes[id] = readFootnoteElement(footnoteElement); - }); - - return new Footnotes(footnotes); + return xml.root.getElementsByTagName("w:footnote").map(readFootnoteElement); } function readFootnoteElement(footnoteElement) { + var id = footnoteElement.attributes["w:id"]; var body = footnoteElement.children; - return {body: body}; + return {id: id, body: body}; } diff --git a/lib/results.js b/lib/results.js index fe9f632..bd66430 100644 --- a/lib/results.js +++ b/lib/results.js @@ -14,6 +14,11 @@ Result.prototype.map = function(func) { return new Result(func(this.value), this.messages); }; +Result.prototype.flatMap = function(func) { + var funcResult = func(this.value); + return new Result(funcResult.value, combineMessages([this, funcResult])); +}; + Result.prototype.flatMapThen = function(func) { var that = this; return func(this.value).then(function(otherResult) { diff --git a/package.json b/package.json index 1ae0d87..7bad258 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "dependencies": { "bluebird": "~1.1.0", "sax": "~0.5.2", - "underscore": "~1.4.4", + "underscore": "~1.6.0", "lop": "~0.2.8", "async": "~0.2.6", "nomnom": "~1.6.2", diff --git a/tests/docx/document-xml-reader.tests.js b/tests/docx/document-xml-reader.tests.js index af43c16..6659735 100644 --- a/tests/docx/document-xml-reader.tests.js +++ b/tests/docx/document-xml-reader.tests.js @@ -21,6 +21,14 @@ function readXmlElementValue(element, options) { return result.value; } +function convertXmlToDocumentValue(element, options) { + options = options || {}; + var reader = new DocumentXmlReader(options); + var result = reader.convertXmlToDocument(element, options); + assert.deepEqual(result.messages, []); + return result.value; +} + var fakeContentTypes = { findContentType: function(path) { return "<content-type: " + path + ">"; @@ -280,6 +288,21 @@ describe("readXmlElement: ", function() { var result = readXmlElement(hyperlinkXml); assert.deepEqual(result.value[0].type, "run"); }); + +}); + +describe("convertXmlToDocument: ", function() { + + test("footnotes of document are read", function() { + var paragraphXml = new XmlElement("w:p", {}, []); + var bodyXml = new XmlElement("w:body", {}, [paragraphXml]); + var documentXml = new XmlElement("w:document", {}, [bodyXml]); + var footnotes = [{id: "4", body: [paragraphXml]}]; + var document = convertXmlToDocumentValue({root: documentXml}, {footnotes: footnotes}); + var footnote = document.footnotes.findFootnoteById("4"); + assert.deepEqual(footnote.id, "4"); + assert.deepEqual(footnote.body[0].type, "paragraph"); + }); }); function runWithProperties(children) { diff --git a/tests/docx/footnotes-reader.tests.js b/tests/docx/footnotes-reader.tests.js index 536fc55..512f477 100644 --- a/tests/docx/footnotes-reader.tests.js +++ b/tests/docx/footnotes-reader.tests.js @@ -8,23 +8,15 @@ var test = require("../testing").test; describe('readFootnotesXml', function() { - test('footnote can be looked up by ID', function() { + test('ID and body of footnote are read', function() { var footnoteBody = [new XmlElement("w:p", {}, [])]; var footnotes = readFootnotesXml({ root: new XmlElement("w:footnotes", {}, [ new XmlElement("w:footnote", {"w:id": "1"}, footnoteBody) ]) }); - assert.strictEqual(footnotes.findFootnoteById("1").body, footnoteBody); - }); - - test('footnote is null if no footnote with that ID exists', function() { - var footnoteBody = [new XmlElement("w:p", {}, [])]; - var footnotes = readFootnotesXml({ - root: new XmlElement("w:footnotes", {}, [ - new XmlElement("w:footnote", {"w:id": "1"}, footnoteBody) - ]) - }); - assert.strictEqual(footnotes.findFootnoteById("2"), null); + assert.equal(footnotes.length, 1); + assert.strictEqual(footnotes[0].body, footnoteBody); + assert.deepEqual(footnotes[0].id, "1"); }); }); diff --git a/tests/mammoth.tests.js b/tests/mammoth.tests.js index 0762bcc..4983849 100644 --- a/tests/mammoth.tests.js +++ b/tests/mammoth.tests.js @@ -92,15 +92,14 @@ describe('mammoth', function() { // TODO: generate unique IDs for footnotes // TODO: generate links back to main body // TODO: don't duplicate footnotes with multiple references - // TODO: not yet implemented - return; var docxPath = path.join(__dirname, "test-data/footnotes.docx"); return mammoth.convertToHtml({path: docxPath}).then(function(result) { var expectedOutput = '<p>Ouch<sup><a href="#footnote-1">1</a></sup>.<sup><a href="#footnote-2">2</a></sup></p>' + '<ol><li id="footnote-1"><p> A tachyon walks into a bar.</p></li>' + '<li id="footnote-2"><p> Fin.</p></li></ol>' assert.equal(result.value, expectedOutput); - assert.deepEqual(result.messages, []); + // TODO: get rid of warnings + //~ assert.deepEqual(result.messages, []); }); }); |
