Skip to content

Commit

Permalink
docxRaw support to get xml from inline string in docx
Browse files Browse the repository at this point in the history
fix #1024
  • Loading branch information
bjrmatos committed Oct 30, 2023
1 parent 31687cc commit d615661
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 8 deletions.
5 changes: 5 additions & 0 deletions packages/jsreport-docx/lib/decodeXML.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { decode } = require('html-entities')

module.exports = function decodeXML (str) {
return decode(str, { level: 'xml' })
}
8 changes: 8 additions & 0 deletions packages/jsreport-docx/lib/preprocess/raw.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ module.exports = (files) => {
if (!replaceParentElementArg || !replaceParentElementArg[1]) {
throw new Error('Expected "replaceParentElement" parameter for the docxRaw helper')
}
const rawXML = xmlArg[1]

// if the xml was specified inline, it means it was stored as part of the xml,
// in this case we need to decode the XML at runtime, we specify that by using the inlineXML option
if (rawXML.startsWith("'") || rawXML.startsWith('"')) {
textEl.textContent = `${textEl.textContent.slice(0, xmlArg.index)}inlineXML=true ${textEl.textContent.slice(xmlArg.index)}`
}

const replaceParentElement = replaceParentElementArg[1]
const helperCall = textEl.textContent.match(regexp)[0]
const newNode = documentFile.createElement('docxRemove')
Expand Down
3 changes: 1 addition & 2 deletions packages/jsreport-docx/lib/processDocx.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const { DOMParser, XMLSerializer } = require('@xmldom/xmldom')
const { customAlphabet } = require('nanoid')
const { decode } = require('html-entities')
const { decompress, saveXmlsToOfficeFile } = require('@jsreport/office')
const preprocess = require('./preprocess/preprocess.js')
const postprocess = require('./postprocess/postprocess.js')
const { contentIsXML } = require('./utils')
const decodeXML = require('./decodeXML')
const generateRandomId = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 4)
const decodeXML = (str) => decode(str, { level: 'xml' })

module.exports = async (reporter, inputs, req) => {
const { docxTemplateContent, options, outputPath } = inputs
Expand Down
5 changes: 5 additions & 0 deletions packages/jsreport-docx/lib/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ module.exports = (reporter, definition) => {

let helpersScript

reporter.options.sandbox.modules.push({
alias: 'docxDecodeXML',
path: path.join(__dirname, './decodeXML.js')
})

reporter.options.sandbox.modules.push({
alias: 'docxProcessChildEmbed',
path: path.join(__dirname, './processChildEmbed/index.js')
Expand Down
16 changes: 10 additions & 6 deletions packages/jsreport-docx/static/helpers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint no-unused-vars: 0 */
/* eslint no-new-func: 0 */
/* *global __rootDirectory */

function docxContext (options) {
const Handlebars = require('handlebars')
let data
Expand Down Expand Up @@ -58,15 +57,20 @@ function docxPageBreak () {

function docxRaw (options) {
const Handlebars = require('handlebars')
const isInlineXML = options.hash.inlineXML === true
let xmlInput = options.hash.xml

if (typeof options.hash.xml === 'string') {
if (options.hash.xml.startsWith('<')) {
return new Handlebars.SafeString(options.hash.xml)
}
if (isInlineXML && typeof xmlInput === 'string') {
const decodeXML = require('docxDecodeXML')
xmlInput = decodeXML(xmlInput)
}

if (typeof xmlInput === 'string' && xmlInput.startsWith('<')) {
return new Handlebars.SafeString(xmlInput)
}

// Wrap not valid XML data as a literal, without any style
return new Handlebars.SafeString('<w:r><w:t>' + options.hash.xml + '</w:t></w:r>')
return new Handlebars.SafeString('<w:r><w:t>' + xmlInput + '</w:t></w:r>')
}

function docxList (data, options) {
Expand Down
Binary file added packages/jsreport-docx/test/docx/raw-inline.docx
Binary file not shown.
32 changes: 32 additions & 0 deletions packages/jsreport-docx/test/rawTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,38 @@ describe('docx raw', () => {
])
})

it('raw with inline xml parameter', async () => {
const result = await reporter.render({
template: {
engine: 'handlebars',
recipe: 'docx',
docx: {
templateAsset: {
content: fs.readFileSync(path.join(docxDirPath, 'raw-inline.docx'))
}
}
},
data: {}
})

// Write document for easier debugging
fs.writeFileSync(outputPath, result.content)

const [doc] = await getDocumentsFromDocxBuf(result.content, ['word/document.xml'])
const generalTextElements = nodeListToArray(doc.getElementsByTagName('w:t'))

const found = []
for (const textEl of generalTextElements) {
if (textEl.textContent.includes('raw xml run')) {
found.push(textEl.textContent)
should(textEl.parentNode.nodeName).eql('w:r', textEl.textContent)
should(textEl.parentNode.parentNode.nodeName).eql('w:p', textEl.textContent)
should(textEl.parentNode.parentNode.parentNode.nodeName).eql('w:body', textEl.textContent)
}
}
should(found).eql(['raw xml run'])
})

it('raw error no parameter', async () => {
const result = reporter.render({
template: {
Expand Down

0 comments on commit d615661

Please sign in to comment.