guigrpa / docx-templates

Template-based docx report creation
MIT License
882 stars 145 forks source link

additionalJsContext always wrapped in text tag breaking styling #349

Open donnellbob opened 7 months ago

donnellbob commented 7 months ago

Hey, I am experiencing various issues when using additionalJsContext to add any additional xml with || delimiter. Looking into it seems like others experiencing similar issues with pagebreak here though seems to apply to most styling.

Note the resulting xml work as expected in Microsoft Word but any other word processor will be without styles.

Example code

const { createReport } = require("docx-templates");
const fs = require("fs");

createReport({
  template: fs.readFileSync("./sampletemplate.docx"),
  data: {},
  cmdDelimiter: ["{{", "}}"],
  additionalJsContext: {
    pagebreak: () => '||<w:br w:type="page" />||',
    customStyledElement: () =>
      `||<w:r><w:rPr><w:color w:val="FF0000" /></w:rPr><w:t>styled text</w:t></w:r>||`,
  },
}).then((buf) => {

  fs.writeFileSync("./demo.docx", buf);
});

With this example template: sampletemplate.docx

Result

With the above sample code / template ("pages" on left, Word on the right). Have also tested in Google Docs and get the same broken styles.

Screenshot 2024-01-30 at 1 32 51 pm

Viewing the document.xml shows the inputted elements are wrapped in w:t

    <w:p w14:paraId="12F5DD50" w14:textId="77777777" w:rsidR="005135B0" w:rsidRDefault="005135B0" w:rsidP="005135B0">
      <w:pPr>
        <w:rPr>
          <w:lang w:val="en-US"/>
        </w:rPr>
      </w:pPr>
      <w:r>
        <w:rPr>
          <w:lang w:val="en-US"/>
        </w:rPr>
        <w:t xml:space="preserve"><w:r><w:rPr><w:color w:val="FF0000" /></w:rPr><w:t>styled text</w:t></w:r></w:t>
      </w:r>
    </w:p>

But when saving the same document with Microsoft Word the XML is corrected to:

    <w:p w14:paraId="12F5DD50" w14:textId="77777777" w:rsidR="005135B0" w:rsidRDefault="005135B0"
      w:rsidP="005135B0">
      <w:pPr>
        <w:rPr>
          <w:lang w:val="en-US" />
        </w:rPr>
      </w:pPr>
      <w:r>
        <w:rPr>
          <w:color w:val="FF0000" />
          <w:lang w:val="en-US" />
        </w:rPr>
        <w:t>styled text</w:t>
      </w:r>
    </w:p>

Let me know if you need any additional information or if there is an existing approach to ensure additionalJsContext elements are wrapped correctly for styling.

jjhbw commented 5 months ago

I'm not super familiar with this functionality, but it seems that MS Word does not think your XML is correct. What do you think docx-templates is doing wrong?

donnellbob commented 5 months ago

@jjhbw As far as I understand its due to way docx-template wraps all additionalJsContext inside of a <w:t> tag. So when attempting to do invalid xml inside of a w:t i.e. page break <w:br w:type="page" /> or stylings it would create invalid XML that Word is later correcting.

As for the solution I am not to sure on the internals on what might be possible. Whether certain tags that are invalid in w:t are hoisted or an option to have additionalJsContext be placed in the <w:r>