docx icon indicating copy to clipboard operation
docx copied to clipboard

How to integrate HTML string into the docx?

Open jurei733 opened this issue 11 months ago • 5 comments

Want to integrate Html strings in my docx file and don't see how to to do it right now ?

jurei733 avatar Mar 07 '24 16:03 jurei733

I'm also interested in this, would it be possible to have this feature?

0biWanKenobi avatar Apr 24 '24 10:04 0biWanKenobi

Same question 🙏

k6c8e4 avatar Apr 25 '24 09:04 k6c8e4

Same here!

EvanPiro avatar May 06 '24 20:05 EvanPiro

I am also interested in this

nastopendo avatar May 07 '24 11:05 nastopendo

Here is a minimal implementation that works for very simple HTML (WYSIWYG outputs).

import { parseFromString } from "dom-parser";
import {
  Document,
  Footer,
  PageNumber,
  Paragraph,
  TextRun,
} from "docx";
import * as he from "he";

export const htmlStrToParagraph = (str: string): Paragraph[] => {
  const dom = parseFromString(`<body>${str}</body>`)
  
  const sectionChildren = [];

  dom.getElementsByTagName("body")[0].childNodes.forEach((node) => {
    if (["h1", "h2", "h3"].includes(node.nodeName)) {
      sectionChildren.push(
        new Paragraph({
          children: [
            new TextRun({
              text: he.decode(node.textContent),
              bold: true,
            }),
          ],
          spacing: { after: 0 },
        })
      );
    } else if (["p"].includes(node.nodeName)) {
      sectionChildren.push(
        new Paragraph({
          children: [
            new TextRun({
              text: he.decode(node.textContent),
            }),
          ],
          spacing: { after: 0 },
        })
      );
    } else if (node.nodeName === "ul") {
      node.childNodes.forEach((bullet) => {
        if (bullet.nodeName === "li") {
          sectionChildren.push(
            new Paragraph({
              text: he.decode(bullet.textContent),
              bullet: {
                level: 0,
              },
              spacing: {
                before: 0,
                after: 0,
              },
            })
          );
        }
      });
    }

    sectionChildren.push(
      new Paragraph({
        text: "",
        spacing: {
          before: 0,
          after: 0,
        },
      })
    );
  });

  return sectionChildren;
};

You can then run it to construct a document:

const htmlStrToDocx = async (str: string): Promise<Document> => {
  return new Document({
    creator: "Me",
    sections: [
      {
        children: htmlStrToParagraph(str),
        footers: {
          default: new Footer({
            children: [
              new Paragraph({
                alignment: AlignmentType.CENTER,
                children: [
                  new TextRun({
                    children: [PageNumber.CURRENT],
                    color: "000000",
                  }),
                ],
              }),
            ],
          }),
        },
      },
    ],
  });
};

EvanPiro avatar May 07 '24 13:05 EvanPiro