works!
This commit is contained in:
BIN
MyDocument.docx
BIN
MyDocument.docx
Binary file not shown.
@ -1,26 +1,25 @@
|
|||||||
import { Document, Packer, Paragraph, ImportDocx } from "../build";
|
import { Document, Packer, Paragraph, ImportDocx } from "../build";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
|
||||||
console.log(process.cwd());
|
|
||||||
|
|
||||||
let importDocx = new ImportDocx();
|
let importDocx = new ImportDocx();
|
||||||
fs.readFile("./src/importDocx/simple.dotx", (err, data) => {
|
const filePath = "./demo/dotx/template.dotx";
|
||||||
|
fs.readFile(filePath, (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.error(`failed to read file ${filePath}.`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
importDocx.read(data).then(xmlComp => {
|
importDocx.extract(data).then(templateDocument => {
|
||||||
console.log(xmlComp);
|
let options = {};
|
||||||
const doc = new Document({templateHeader : xmlComp});
|
options['templateDocument'] = templateDocument;
|
||||||
// const doc = new Document();
|
|
||||||
|
const doc = new Document(options);
|
||||||
const paragraph = new Paragraph("Hello World");
|
const paragraph = new Paragraph("Hello World");
|
||||||
doc.addParagraph(paragraph);
|
doc.addParagraph(paragraph);
|
||||||
|
|
||||||
// console.log(JSON.stringify(xmlComp, null, 2));
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
|
||||||
packer.toBuffer(doc).then((buffer) => {
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
fs.writeFileSync("MyDocument.docx", buffer);
|
fs.writeFileSync("MyDocument.docx", buffer);
|
||||||
|
console.log('done. open MyDocument.docx');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
BIN
demo/dotx/simple.dotx
Normal file
BIN
demo/dotx/simple.dotx
Normal file
Binary file not shown.
BIN
demo/dotx/simple2.dotx
Normal file
BIN
demo/dotx/simple2.dotx
Normal file
Binary file not shown.
@ -1,13 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
exports.__esModule = true;
|
|
||||||
var build_1 = require("../build");
|
|
||||||
var fs = require("fs");
|
|
||||||
var importDocx = new build_1.ImportDocx();
|
|
||||||
fs.readFile("./src/import/template.dotx", function (err, data) {
|
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
importDocx.read(data);
|
|
||||||
}
|
|
||||||
});
|
|
@ -53,10 +53,21 @@ export class Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (const data of file.Media.Array) {
|
for (const data of file.Media.Array) {
|
||||||
const mediaData = data.stream;
|
const mediaData = data.stream;
|
||||||
zip.file(`word/media/${data.fileName}`, mediaData);
|
zip.file(`word/media/${data.fileName}`, mediaData);
|
||||||
}
|
}
|
||||||
|
for (let header of file.Headers) {
|
||||||
|
for (const data of header.media.Array) {
|
||||||
|
zip.file(`word/media/${data.fileName}`, data.stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let footer of file.Footers) {
|
||||||
|
for (const data of footer.media.Array) {
|
||||||
|
zip.file(`word/media/${data.fileName}`, data.stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return zip;
|
return zip;
|
||||||
}
|
}
|
||||||
@ -122,4 +133,13 @@ export class Compiler {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* By default docx collapse empty tags. <a></a> -> <a/>. this function mimic it
|
||||||
|
so comparing (diff) original docx file and the library output is easier */
|
||||||
|
collapseEmptyTags(xmlData : string) : string {
|
||||||
|
const regEx = /<(([^ <>]+)[^<>]*)><\/\2>/g;
|
||||||
|
let collapsed = xmlData.replace(regEx, '<$1/>');
|
||||||
|
return collapsed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
import { DocumentAttributes } from "../document/document-attributes";
|
import { DocumentAttributes } from "../document/document-attributes";
|
||||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||||
|
|
||||||
|
import { TemplateDocument } from 'importDocx/importDocx'
|
||||||
|
|
||||||
export interface IPropertiesOptions {
|
export interface IPropertiesOptions {
|
||||||
title?: string;
|
title?: string;
|
||||||
subject?: string;
|
subject?: string;
|
||||||
@ -12,7 +14,7 @@ export interface IPropertiesOptions {
|
|||||||
revision?: string;
|
revision?: string;
|
||||||
externalStyles?: string;
|
externalStyles?: string;
|
||||||
|
|
||||||
templateHeader? : XmlComponent;
|
templateDocument? : TemplateDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CoreProperties extends XmlComponent {
|
export class CoreProperties extends XmlComponent {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../../../export/formatter";
|
import { Formatter } from "../../../../export/formatter";
|
||||||
import { FooterReferenceType, PageBorderOffsetFrom, PageNumberFormat } from "./";
|
import { PageBorderOffsetFrom, PageNumberFormat, FooterReferenceType, HeaderReferenceType } from "./";
|
||||||
import { SectionProperties } from "./section-properties";
|
import { SectionProperties } from "./section-properties";
|
||||||
|
|
||||||
describe("SectionProperties", () => {
|
describe("SectionProperties", () => {
|
||||||
@ -19,9 +19,8 @@ describe("SectionProperties", () => {
|
|||||||
gutter: 0,
|
gutter: 0,
|
||||||
space: 708,
|
space: 708,
|
||||||
linePitch: 360,
|
linePitch: 360,
|
||||||
headerId: 100,
|
headers: [{headerId: 100, headerType: HeaderReferenceType.DEFAULT}],
|
||||||
footerId: 200,
|
footers: [{footerId: 200, footerType: FooterReferenceType.EVEN}],
|
||||||
footerType: FooterReferenceType.EVEN,
|
|
||||||
pageNumberStart: 10,
|
pageNumberStart: 10,
|
||||||
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
|
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
|
||||||
});
|
});
|
||||||
|
@ -1,24 +1,27 @@
|
|||||||
// http://officeopenxml.com/WPsection.php
|
// http://officeopenxml.com/WPsection.php
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { FooterReferenceType, IPageBordersOptions, IPageNumberTypeAttributes, PageBorders, PageNumberFormat, PageNumberType } from "./";
|
import { IPageBordersOptions, IPageNumberTypeAttributes, PageBorders, PageNumberFormat, PageNumberType } from "./";
|
||||||
import { Columns } from "./columns/columns";
|
import { Columns } from "./columns/columns";
|
||||||
import { IColumnsAttributes } from "./columns/columns-attributes";
|
import { IColumnsAttributes } from "./columns/columns-attributes";
|
||||||
import { DocumentGrid } from "./doc-grid/doc-grid";
|
import { DocumentGrid } from "./doc-grid/doc-grid";
|
||||||
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
|
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
|
||||||
import { FooterReference, IFooterOptions } from "./footer-reference/footer-reference";
|
import { FooterReference, IFooterOptions } from "./footer-reference/footer-reference";
|
||||||
import { HeaderReference, IHeaderOptions } from "./header-reference/header-reference";
|
import { HeaderReference, IHeaderOptions } from "./header-reference/header-reference";
|
||||||
import { HeaderReferenceType } from "./header-reference/header-reference-attributes";
|
|
||||||
import { PageMargin } from "./page-margin/page-margin";
|
import { PageMargin } from "./page-margin/page-margin";
|
||||||
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
|
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
|
||||||
import { PageSize } from "./page-size/page-size";
|
import { PageSize } from "./page-size/page-size";
|
||||||
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
|
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
|
||||||
|
import { TitlePage } from "./title-page/title-page";
|
||||||
|
|
||||||
|
type IHeadersOptions = {headers? : IHeaderOptions[]}
|
||||||
|
type IFootersOptions = {footers? : IFooterOptions[]}
|
||||||
|
|
||||||
export type SectionPropertiesOptions = IPageSizeAttributes &
|
export type SectionPropertiesOptions = IPageSizeAttributes &
|
||||||
IPageMarginAttributes &
|
IPageMarginAttributes &
|
||||||
IColumnsAttributes &
|
IColumnsAttributes &
|
||||||
IDocGridAttributesProperties &
|
IDocGridAttributesProperties &
|
||||||
IHeaderOptions &
|
IHeadersOptions &
|
||||||
IFooterOptions &
|
IFootersOptions &
|
||||||
IPageNumberTypeAttributes &
|
IPageNumberTypeAttributes &
|
||||||
IPageBordersOptions;
|
IPageBordersOptions;
|
||||||
|
|
||||||
@ -41,10 +44,8 @@ export class SectionProperties extends XmlComponent {
|
|||||||
space: 708,
|
space: 708,
|
||||||
linePitch: 360,
|
linePitch: 360,
|
||||||
orientation: PageOrientation.PORTRAIT,
|
orientation: PageOrientation.PORTRAIT,
|
||||||
headerType: HeaderReferenceType.DEFAULT,
|
headers: [],
|
||||||
headerId: 0,
|
footers: [],
|
||||||
footerType: FooterReferenceType.DEFAULT,
|
|
||||||
footerId: 0,
|
|
||||||
pageNumberStart: undefined,
|
pageNumberStart: undefined,
|
||||||
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||||
pageBorders: undefined,
|
pageBorders: undefined,
|
||||||
@ -52,6 +53,7 @@ export class SectionProperties extends XmlComponent {
|
|||||||
pageBorderRight: undefined,
|
pageBorderRight: undefined,
|
||||||
pageBorderBottom: undefined,
|
pageBorderBottom: undefined,
|
||||||
pageBorderLeft: undefined,
|
pageBorderLeft: undefined,
|
||||||
|
titlePage : true
|
||||||
};
|
};
|
||||||
|
|
||||||
const mergedOptions = {
|
const mergedOptions = {
|
||||||
@ -59,6 +61,7 @@ export class SectionProperties extends XmlComponent {
|
|||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
this.root.push(new PageSize(mergedOptions.width, mergedOptions.height, mergedOptions.orientation));
|
this.root.push(new PageSize(mergedOptions.width, mergedOptions.height, mergedOptions.orientation));
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new PageMargin(
|
new PageMargin(
|
||||||
@ -74,18 +77,23 @@ export class SectionProperties extends XmlComponent {
|
|||||||
this.root.push(new Columns(mergedOptions.space));
|
this.root.push(new Columns(mergedOptions.space));
|
||||||
this.root.push(new DocumentGrid(mergedOptions.linePitch));
|
this.root.push(new DocumentGrid(mergedOptions.linePitch));
|
||||||
|
|
||||||
|
for (let header of mergedOptions.headers) {
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new HeaderReference({
|
new HeaderReference({
|
||||||
headerType: mergedOptions.headerType,
|
headerType: header.headerType,
|
||||||
headerId: mergedOptions.headerId,
|
headerId: header.headerId,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let footer of mergedOptions.footers) {
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new FooterReference({
|
new FooterReference({
|
||||||
footerType: mergedOptions.footerType,
|
footerType: footer.footerType,
|
||||||
footerId: mergedOptions.footerId,
|
footerId: footer.footerId,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.root.push(new PageNumberType(mergedOptions.pageNumberStart, mergedOptions.pageNumberFormatType));
|
this.root.push(new PageNumberType(mergedOptions.pageNumberStart, mergedOptions.pageNumberFormatType));
|
||||||
|
|
||||||
@ -107,6 +115,10 @@ export class SectionProperties extends XmlComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mergedOptions.titlePage) {
|
||||||
|
this.root.push(new TitlePage());
|
||||||
|
}
|
||||||
|
|
||||||
this.options = mergedOptions;
|
this.options = mergedOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
125
src/file/file.ts
125
src/file/file.ts
@ -2,7 +2,14 @@ import { AppProperties } from "./app-properties/app-properties";
|
|||||||
import { ContentTypes } from "./content-types/content-types";
|
import { ContentTypes } from "./content-types/content-types";
|
||||||
import { CoreProperties, IPropertiesOptions } from "./core-properties";
|
import { CoreProperties, IPropertiesOptions } from "./core-properties";
|
||||||
import { Document } from "./document";
|
import { Document } from "./document";
|
||||||
import { FooterReferenceType, HeaderReference, HeaderReferenceType, SectionPropertiesOptions } from "./document/body/section-properties";
|
import {
|
||||||
|
FooterReferenceType,
|
||||||
|
HeaderReference,
|
||||||
|
HeaderReferenceType,
|
||||||
|
SectionPropertiesOptions,
|
||||||
|
IHeaderOptions,
|
||||||
|
IFooterOptions,
|
||||||
|
} from "./document/body/section-properties";
|
||||||
import { FooterWrapper } from "./footer-wrapper";
|
import { FooterWrapper } from "./footer-wrapper";
|
||||||
import { FootNotes } from "./footnotes";
|
import { FootNotes } from "./footnotes";
|
||||||
import { HeaderWrapper } from "./header-wrapper";
|
import { HeaderWrapper } from "./header-wrapper";
|
||||||
@ -14,7 +21,9 @@ import { Styles } from "./styles";
|
|||||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||||
import { DefaultStylesFactory } from "./styles/factory";
|
import { DefaultStylesFactory } from "./styles/factory";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
import { XmlComponent } from "./xml-components";
|
|
||||||
|
type DocumentHeaders = { header: HeaderWrapper; type: HeaderReferenceType }[];
|
||||||
|
type DocumentFooters = { footer: FooterWrapper; type: FooterReferenceType }[];
|
||||||
|
|
||||||
export class File {
|
export class File {
|
||||||
private readonly document: Document;
|
private readonly document: Document;
|
||||||
@ -24,8 +33,9 @@ export class File {
|
|||||||
private readonly media: Media;
|
private readonly media: Media;
|
||||||
private readonly docRelationships: Relationships;
|
private readonly docRelationships: Relationships;
|
||||||
private readonly fileRelationships: Relationships;
|
private readonly fileRelationships: Relationships;
|
||||||
private readonly headerWrapper: HeaderWrapper[] = [];
|
private readonly documentHeaders: DocumentHeaders = [];
|
||||||
private readonly footerWrapper: FooterWrapper[] = [];
|
private readonly documentFooters: DocumentFooters = [];
|
||||||
|
|
||||||
private readonly footNotes: FootNotes;
|
private readonly footNotes: FootNotes;
|
||||||
|
|
||||||
private readonly contentTypes: ContentTypes;
|
private readonly contentTypes: ContentTypes;
|
||||||
@ -42,6 +52,11 @@ export class File {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const templateDocument = options.templateDocument;
|
||||||
|
if (templateDocument) {
|
||||||
|
this.currentRelationshipId = templateDocument.currentRelationshipId + 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.externalStyles) {
|
if (options.externalStyles) {
|
||||||
const stylesFactory = new ExternalStylesFactory();
|
const stylesFactory = new ExternalStylesFactory();
|
||||||
this.styles = stylesFactory.newInstance(options.externalStyles);
|
this.styles = stylesFactory.newInstance(options.externalStyles);
|
||||||
@ -52,6 +67,7 @@ export class File {
|
|||||||
|
|
||||||
this.coreProperties = new CoreProperties(options);
|
this.coreProperties = new CoreProperties(options);
|
||||||
this.numbering = new Numbering();
|
this.numbering = new Numbering();
|
||||||
|
|
||||||
this.docRelationships = new Relationships();
|
this.docRelationships = new Relationships();
|
||||||
this.docRelationships.createRelationship(
|
this.docRelationships.createRelationship(
|
||||||
this.currentRelationshipId++,
|
this.currentRelationshipId++,
|
||||||
@ -70,10 +86,26 @@ export class File {
|
|||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
|
||||||
"footnotes.xml",
|
"footnotes.xml",
|
||||||
);
|
);
|
||||||
|
|
||||||
this.media = new Media();
|
this.media = new Media();
|
||||||
|
|
||||||
const header = this.createHeader(options.templateHeader);
|
const templateHeaders = templateDocument && templateDocument.headers;
|
||||||
const footer = this.createFooter();
|
if (!templateHeaders) {
|
||||||
|
this.createHeader();
|
||||||
|
} else {
|
||||||
|
for (let templateHeader of templateHeaders) {
|
||||||
|
this.addHeaderToDocument(templateHeader.header, templateHeader.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateFooters = templateDocument && templateDocument.footers;
|
||||||
|
if (!templateFooters) {
|
||||||
|
this.createFooter();
|
||||||
|
} else {
|
||||||
|
for (let templateFooter of templateFooters) {
|
||||||
|
this.addFooterToDocument(templateFooter.footer, templateFooter.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.fileRelationships = new Relationships();
|
this.fileRelationships = new Relationships();
|
||||||
this.fileRelationships.createRelationship(
|
this.fileRelationships.createRelationship(
|
||||||
@ -94,17 +126,34 @@ export class File {
|
|||||||
this.appProperties = new AppProperties();
|
this.appProperties = new AppProperties();
|
||||||
|
|
||||||
this.footNotes = new FootNotes();
|
this.footNotes = new FootNotes();
|
||||||
|
|
||||||
|
let headersOptions: IHeaderOptions[] = [];
|
||||||
|
for (let documentHeader of this.documentHeaders) {
|
||||||
|
headersOptions.push({
|
||||||
|
headerId: documentHeader.header.Header.ReferenceId,
|
||||||
|
headerType: documentHeader.type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let footersOptions: IFooterOptions[] = [];
|
||||||
|
for (let documentFooter of this.documentFooters) {
|
||||||
|
footersOptions.push({
|
||||||
|
footerId: documentFooter.footer.Footer.ReferenceId,
|
||||||
|
footerType: documentFooter.type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!sectionPropertiesOptions) {
|
if (!sectionPropertiesOptions) {
|
||||||
sectionPropertiesOptions = {
|
sectionPropertiesOptions = {
|
||||||
footerType: FooterReferenceType.DEFAULT,
|
headers: headersOptions,
|
||||||
headerType: HeaderReferenceType.DEFAULT,
|
footers: footersOptions,
|
||||||
headerId: header.Header.ReferenceId,
|
|
||||||
footerId: footer.Footer.ReferenceId,
|
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
sectionPropertiesOptions.headerId = header.Header.ReferenceId;
|
|
||||||
sectionPropertiesOptions.footerId = footer.Footer.ReferenceId;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
sectionPropertiesOptions.headers = headersOptions;
|
||||||
|
sectionPropertiesOptions.footers = footersOptions;
|
||||||
|
}
|
||||||
|
|
||||||
this.document = new Document(sectionPropertiesOptions);
|
this.document = new Document(sectionPropertiesOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,30 +219,36 @@ export class File {
|
|||||||
this.footNotes.createFootNote(paragraph);
|
this.footNotes.createFootNote(paragraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createHeader(templateHeader? : XmlComponent): HeaderWrapper {
|
public createHeader(): HeaderWrapper {
|
||||||
const header = new HeaderWrapper(this.media, this.currentRelationshipId++, templateHeader);
|
const header = new HeaderWrapper(this.currentRelationshipId++);
|
||||||
console.log('\n\n-------\n\n');
|
this.addHeaderToDocument(header);
|
||||||
console.log('header', JSON.stringify(header.Header, null, 2));
|
|
||||||
this.headerWrapper.push(header);
|
|
||||||
this.docRelationships.createRelationship(
|
|
||||||
header.Header.ReferenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
|
|
||||||
`header${this.headerWrapper.length}.xml`,
|
|
||||||
);
|
|
||||||
this.contentTypes.addHeader(this.headerWrapper.length);
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT) {
|
||||||
|
this.documentHeaders.push({ header, type });
|
||||||
|
this.docRelationships.createRelationship(
|
||||||
|
header.Header.ReferenceId,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
|
||||||
|
`header${this.documentHeaders.length}.xml`,
|
||||||
|
);
|
||||||
|
this.contentTypes.addHeader(this.documentHeaders.length);
|
||||||
|
}
|
||||||
|
|
||||||
public createFooter(): FooterWrapper {
|
public createFooter(): FooterWrapper {
|
||||||
const footer = new FooterWrapper(this.media, this.currentRelationshipId++);
|
const footer = new FooterWrapper(this.currentRelationshipId++);
|
||||||
this.footerWrapper.push(footer);
|
this.addFooterToDocument(footer);
|
||||||
|
return footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addFooterToDocument(footer: FooterWrapper, type: FooterReferenceType = FooterReferenceType.DEFAULT) {
|
||||||
|
this.documentFooters.push({ footer, type });
|
||||||
this.docRelationships.createRelationship(
|
this.docRelationships.createRelationship(
|
||||||
footer.Footer.ReferenceId,
|
footer.Footer.ReferenceId,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
|
||||||
`footer${this.footerWrapper.length}.xml`,
|
`footer${this.documentFooters.length}.xml`,
|
||||||
);
|
);
|
||||||
this.contentTypes.addFooter(this.footerWrapper.length);
|
this.contentTypes.addFooter(this.documentFooters.length);
|
||||||
return footer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public createFirstPageHeader(): HeaderWrapper {
|
public createFirstPageHeader(): HeaderWrapper {
|
||||||
@ -238,15 +293,15 @@ export class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get Header(): HeaderWrapper {
|
public get Header(): HeaderWrapper {
|
||||||
return this.headerWrapper[0];
|
return this.documentHeaders[0].header;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Headers(): HeaderWrapper[] {
|
public get Headers(): HeaderWrapper[] {
|
||||||
return this.headerWrapper;
|
return this.documentHeaders.map((item) => item.header);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeaderByRefNumber(refId: number): HeaderWrapper {
|
public HeaderByRefNumber(refId: number): HeaderWrapper {
|
||||||
const entry = this.headerWrapper.find((h) => h.Header.ReferenceId === refId);
|
const entry = this.documentHeaders.map((item) => item.header).find((h) => h.Header.ReferenceId === refId);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -254,15 +309,15 @@ export class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get Footer(): FooterWrapper {
|
public get Footer(): FooterWrapper {
|
||||||
return this.footerWrapper[0];
|
return this.documentFooters[0].footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Footers(): FooterWrapper[] {
|
public get Footers(): FooterWrapper[] {
|
||||||
return this.footerWrapper;
|
return this.documentFooters.map((item) => item.footer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FooterByRefNumber(refId: number): FooterWrapper {
|
public FooterByRefNumber(refId: number): FooterWrapper {
|
||||||
const entry = this.footerWrapper.find((h) => h.Footer.ReferenceId === refId);
|
const entry = this.documentFooters.map((item) => item.footer).find((h) => h.Footer.ReferenceId === refId);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,17 @@ import { Image, Media } from "./media";
|
|||||||
import { ImageParagraph, Paragraph } from "./paragraph";
|
import { ImageParagraph, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
|
import { IMediaData } from 'file/media';
|
||||||
|
|
||||||
export class FooterWrapper {
|
export class FooterWrapper {
|
||||||
private readonly footer: Footer;
|
private readonly footer: Footer;
|
||||||
private readonly relationships: Relationships;
|
private readonly relationships: Relationships;
|
||||||
|
public readonly media = new Media();
|
||||||
|
|
||||||
constructor(private readonly media: Media, referenceId: number) {
|
constructor(referenceId: number, initContent? : XmlComponent) {
|
||||||
this.footer = new Footer(referenceId);
|
this.footer = new Footer(referenceId, initContent);
|
||||||
this.relationships = new Relationships();
|
this.relationships = new Relationships();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public addParagraph(paragraph: Paragraph): void {
|
public addParagraph(paragraph: Paragraph): void {
|
||||||
@ -36,16 +39,22 @@ export class FooterWrapper {
|
|||||||
this.footer.addChildElement(childElement);
|
this.footer.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createImage(image: Buffer, width?: number, height?: number): void {
|
public addImageRelation(image: Buffer, refId : number, width?: number, height?: number) : IMediaData {
|
||||||
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
|
const mediaData = this.media.addMedia(image, refId, width, height);
|
||||||
this.relationships.createRelationship(
|
this.relationships.createRelationship(
|
||||||
mediaData.referenceId,
|
refId,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
`media/${mediaData.fileName}`,
|
`media/${mediaData.fileName}`,
|
||||||
);
|
);
|
||||||
|
return mediaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public createImage(image: Buffer, width?: number, height?: number): void {
|
||||||
|
let mediaData = this.addImageRelation(image, this.relationships.RelationshipCount, width, height);
|
||||||
this.addImage(new Image(new ImageParagraph(mediaData)));
|
this.addImage(new Image(new ImageParagraph(mediaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public addImage(image: Image): FooterWrapper {
|
public addImage(image: Image): FooterWrapper {
|
||||||
this.footer.addParagraph(image.Paragraph);
|
this.footer.addParagraph(image.Paragraph);
|
||||||
return this;
|
return this;
|
||||||
|
@ -7,8 +7,8 @@ import { FooterAttributes } from "./footer-attributes";
|
|||||||
export class Footer extends XmlComponent {
|
export class Footer extends XmlComponent {
|
||||||
private readonly refId: number;
|
private readonly refId: number;
|
||||||
|
|
||||||
constructor(referenceNumber: number) {
|
constructor(referenceNumber: number, initContent? : XmlComponent) {
|
||||||
super("w:ftr");
|
super("w:ftr", initContent);
|
||||||
this.refId = referenceNumber;
|
this.refId = referenceNumber;
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new FooterAttributes({
|
new FooterAttributes({
|
||||||
|
@ -4,13 +4,16 @@ import { Image, Media } from "./media";
|
|||||||
import { ImageParagraph, Paragraph } from "./paragraph";
|
import { ImageParagraph, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
|
import { IMediaData } from 'file/media';
|
||||||
|
|
||||||
|
|
||||||
export class HeaderWrapper {
|
export class HeaderWrapper {
|
||||||
private readonly header: Header;
|
private readonly header: Header;
|
||||||
private readonly relationships: Relationships;
|
private readonly relationships: Relationships;
|
||||||
|
public readonly media = new Media();
|
||||||
|
|
||||||
constructor(private readonly media: Media, referenceId: number, initContent? : XmlComponent) {
|
// constructor(private readonly media: Media, referenceId: number, initContent? : XmlComponent) {
|
||||||
|
constructor(referenceId: number, initContent? : XmlComponent) {
|
||||||
this.header = new Header(referenceId, initContent);
|
this.header = new Header(referenceId, initContent);
|
||||||
this.relationships = new Relationships();
|
this.relationships = new Relationships();
|
||||||
}
|
}
|
||||||
@ -37,13 +40,18 @@ export class HeaderWrapper {
|
|||||||
this.header.addChildElement(childElement);
|
this.header.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createImage(image: Buffer, width?: number, height?: number): void {
|
public addImageRelation(image: Buffer, refId : number, width?: number, height?: number) : IMediaData {
|
||||||
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
|
const mediaData = this.media.addMedia(image, refId, width, height);
|
||||||
this.relationships.createRelationship(
|
this.relationships.createRelationship(
|
||||||
mediaData.referenceId,
|
refId,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
`media/${mediaData.fileName}`,
|
`media/${mediaData.fileName}`,
|
||||||
);
|
);
|
||||||
|
return mediaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public createImage(image: Buffer, width?: number, height?: number): void {
|
||||||
|
let mediaData = this.addImageRelation(image, this.relationships.RelationshipCount, width, height);
|
||||||
this.addImage(new Image(new ImageParagraph(mediaData)));
|
this.addImage(new Image(new ImageParagraph(mediaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,17 @@ export interface IHeaderAttributesProperties {
|
|||||||
dcmitype?: string;
|
dcmitype?: string;
|
||||||
xsi?: string;
|
xsi?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
|
cx? : string,
|
||||||
|
cx1? : string,
|
||||||
|
cx2? : string,
|
||||||
|
cx3? : string,
|
||||||
|
cx4? : string,
|
||||||
|
cx5? : string,
|
||||||
|
cx6? : string,
|
||||||
|
cx7? : string,
|
||||||
|
cx8? : string,
|
||||||
|
w16cid: string,
|
||||||
|
w16se: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesProperties> {
|
export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesProperties> {
|
||||||
@ -49,5 +60,16 @@ export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesPro
|
|||||||
dcmitype: "xmlns:dcmitype",
|
dcmitype: "xmlns:dcmitype",
|
||||||
xsi: "xmlns:xsi",
|
xsi: "xmlns:xsi",
|
||||||
type: "xsi:type",
|
type: "xsi:type",
|
||||||
|
cx : "xmlns:cx",
|
||||||
|
cx1: "xmlns:cx1",
|
||||||
|
cx2: "xmlns:cx2",
|
||||||
|
cx3: "xmlns:cx3",
|
||||||
|
cx4: "xmlns:cx4",
|
||||||
|
cx5: "xmlns:cx5",
|
||||||
|
cx6: "xmlns:cx6",
|
||||||
|
cx7: "xmlns:cx7",
|
||||||
|
cx8: "xmlns:cx8",
|
||||||
|
w16cid: "xmlns:w16cid",
|
||||||
|
w16se: "xmlns:w16se"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,17 @@ export class Header extends XmlComponent {
|
|||||||
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
|
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
|
||||||
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
|
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
|
||||||
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
|
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
|
||||||
|
cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
|
||||||
|
cx1: "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
|
||||||
|
cx2: "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
|
||||||
|
cx3: "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
|
||||||
|
cx4: "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
|
||||||
|
cx5: "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
|
||||||
|
cx6: "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
|
||||||
|
cx7: "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
|
||||||
|
cx8: "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
|
||||||
|
w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
|
||||||
|
w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex"
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ export const parseOptions = {
|
|||||||
ignoreAttributes: false,
|
ignoreAttributes: false,
|
||||||
attributeNamePrefix: "",
|
attributeNamePrefix: "",
|
||||||
attrNodeName: "_attr",
|
attrNodeName: "_attr",
|
||||||
|
textNodeName: '',
|
||||||
|
trimValues: false
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +59,7 @@ export class ImportedXmlComponent extends XmlComponent {
|
|||||||
private _attr: any;
|
private _attr: any;
|
||||||
|
|
||||||
constructor(rootKey: string, _attr?: any) {
|
constructor(rootKey: string, _attr?: any) {
|
||||||
|
|
||||||
super(rootKey);
|
super(rootKey);
|
||||||
if (_attr) {
|
if (_attr) {
|
||||||
this._attr = _attr;
|
this._attr = _attr;
|
||||||
|
@ -8,12 +8,6 @@ export abstract class XmlComponent extends BaseXmlComponent {
|
|||||||
constructor(rootKey: string, initContent? : XmlComponent) {
|
constructor(rootKey: string, initContent? : XmlComponent) {
|
||||||
super(rootKey);
|
super(rootKey);
|
||||||
this.root = initContent ? initContent.root : new Array<BaseXmlComponent>();
|
this.root = initContent ? initContent.root : new Array<BaseXmlComponent>();
|
||||||
if (initContent) {
|
|
||||||
console.log('\n\n-------\n\n');
|
|
||||||
console.log('new root', JSON.stringify(initContent, null,2));
|
|
||||||
console.log('\n\n-------\n\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public prepForXml(): IXmlableObject {
|
public prepForXml(): IXmlableObject {
|
||||||
@ -30,7 +24,7 @@ export abstract class XmlComponent extends BaseXmlComponent {
|
|||||||
}
|
}
|
||||||
return comp;
|
return comp;
|
||||||
})
|
})
|
||||||
.filter((comp) => comp); // Exclude null, undefined, and empty strings
|
.filter((comp) => comp !== null); // Exclude null, undefined, and empty strings
|
||||||
return {
|
return {
|
||||||
[this.rootKey]: children,
|
[this.rootKey]: children,
|
||||||
};
|
};
|
||||||
|
@ -1,27 +1,152 @@
|
|||||||
import * as JSZip from "jszip";
|
import * as JSZip from "jszip";
|
||||||
import * as fastXmlParser from "fast-xml-parser";
|
import * as fastXmlParser from "fast-xml-parser";
|
||||||
import { convertToXmlComponent, parseOptions, ImportedXmlComponent } from "file/xml-components";
|
import { convertToXmlComponent, parseOptions, ImportedXmlComponent } from "file/xml-components";
|
||||||
|
import { HeaderWrapper } from 'file/header-wrapper';
|
||||||
|
import { FooterWrapper } from 'file/footer-wrapper';
|
||||||
|
import { HeaderReferenceType } from 'file/document/body/section-properties/header-reference';
|
||||||
|
import { FooterReferenceType } from 'file/document/body/section-properties/footer-reference';
|
||||||
|
// import { RelationshipType } from 'file/relationships/relationship/relationship';
|
||||||
|
|
||||||
|
const schemeToType = {
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" : 'header',
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" : 'footer',
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" : 'image',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DocumentRefs {
|
||||||
|
headers : {id : number, type: HeaderReferenceType}[],
|
||||||
|
footers : {id : number, type: FooterReferenceType}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type RelationFileInfo = {id : number, targetFile: string, type: 'header' | 'footer' | 'image'};
|
||||||
|
|
||||||
|
type DocumentHeaders = {type : HeaderReferenceType, header : HeaderWrapper}[];
|
||||||
|
type DocumentFooters = {type : FooterReferenceType, footer : FooterWrapper}[];
|
||||||
|
|
||||||
|
export interface TemplateDocument {
|
||||||
|
currentRelationshipId : number;
|
||||||
|
headers : DocumentHeaders,
|
||||||
|
footers : DocumentFooters,
|
||||||
|
}
|
||||||
|
|
||||||
export class ImportDocx {
|
export class ImportDocx {
|
||||||
|
|
||||||
|
private currentRelationshipId: number = 1;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
read(data) : Promise<any> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
JSZip.loadAsync(data).then((zipContent) => {
|
|
||||||
let headerContent = zipContent['files']['word/header2.xml'];
|
|
||||||
|
|
||||||
headerContent.async('text').then((xmlData : string) => {
|
|
||||||
console.log('\n\n-------\n\n');
|
async extract(data : Buffer) : Promise<TemplateDocument> {
|
||||||
console.log('headerContent', JSON.stringify(xmlData, null, 2));
|
let zipContent = await JSZip.loadAsync(data);
|
||||||
console.log('\n\n-------\n\n');
|
|
||||||
const jsonObj = fastXmlParser.parse(xmlData, parseOptions);
|
let documentContent = zipContent['files']['word/document.xml'];
|
||||||
let xmlComp = convertToXmlComponent('w:hdr', jsonObj['w:hdr']) as ImportedXmlComponent;
|
const documentRefs : DocumentRefs = this.extractDocumentRefs(await documentContent.async('text'))
|
||||||
resolve(xmlComp);
|
|
||||||
|
let relationshipContent = zipContent['files']['word/_rels/document.xml.rels'];
|
||||||
|
const documentRelations : RelationFileInfo[] = this.findReferenceFiles(await relationshipContent.async('text'));
|
||||||
|
|
||||||
|
let headers : DocumentHeaders = [];
|
||||||
|
for(let headerRef of documentRefs.headers) {
|
||||||
|
const headerKey = 'w:hdr';
|
||||||
|
const relationFileInfo = documentRelations.find(rel => rel.id === headerRef.id);
|
||||||
|
if (relationFileInfo == null) {
|
||||||
|
throw `can not find target file for id ${headerRef.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const xmlData = await zipContent['files'][`word/${relationFileInfo.targetFile}`].async('text');
|
||||||
|
const xmlObj = fastXmlParser.parse(xmlData, parseOptions);
|
||||||
|
|
||||||
|
let importedComp = convertToXmlComponent(headerKey, xmlObj[headerKey]) as ImportedXmlComponent;
|
||||||
|
|
||||||
|
let header = new HeaderWrapper(this.currentRelationshipId++, importedComp);
|
||||||
|
await this.addImagesToWrapper(relationFileInfo, zipContent, header);
|
||||||
|
headers.push({type : headerRef.type, header})
|
||||||
|
}
|
||||||
|
|
||||||
|
let footers : DocumentFooters = [];
|
||||||
|
for(let footerRef of documentRefs.footers) {
|
||||||
|
const footerKey = 'w:ftr'
|
||||||
|
const relationFileInfo = documentRelations.find(rel => rel.id === footerRef.id);
|
||||||
|
if (relationFileInfo == null) {
|
||||||
|
throw `can not find target file for id ${footerRef.id}`;
|
||||||
|
}
|
||||||
|
const xmlData = await zipContent['files'][`word/${relationFileInfo.targetFile}`].async('text');
|
||||||
|
const xmlObj = fastXmlParser.parse(xmlData, parseOptions);
|
||||||
|
let importedComp = convertToXmlComponent(footerKey, xmlObj[footerKey]) as ImportedXmlComponent;
|
||||||
|
|
||||||
|
let footer = new FooterWrapper(this.currentRelationshipId++, importedComp);
|
||||||
|
await this.addImagesToWrapper(relationFileInfo, zipContent, footer);
|
||||||
|
footers.push({type : footerRef.type, footer})
|
||||||
|
}
|
||||||
|
|
||||||
|
let templateDocument : TemplateDocument = {headers, footers, currentRelationshipId : this.currentRelationshipId}
|
||||||
|
return templateDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addImagesToWrapper(relationFile : RelationFileInfo, zipContent, wrapper : HeaderWrapper | FooterWrapper) {
|
||||||
|
let wrapperImagesReferences : RelationFileInfo[] = [];
|
||||||
|
const refFile = zipContent['files'][`word/_rels/${relationFile.targetFile}.rels`];
|
||||||
|
if (refFile) {
|
||||||
|
const xmlRef = await refFile.async('text');
|
||||||
|
wrapperImagesReferences = this.findReferenceFiles(xmlRef).filter(r => r.type === 'image');
|
||||||
|
}
|
||||||
|
for (let r of wrapperImagesReferences) {
|
||||||
|
const buffer = await zipContent['files'][`word/${r.targetFile}`].async('nodebuffer');
|
||||||
|
wrapper.addImageRelation(buffer, r.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
findReferenceFiles(xmlData : string) : RelationFileInfo[] {
|
||||||
|
const xmlObj = fastXmlParser.parse(xmlData, parseOptions);
|
||||||
|
const relationXmlArray = Array.isArray(xmlObj['Relationships']['Relationship']) ? xmlObj['Relationships']['Relationship'] : [xmlObj['Relationships']['Relationship']];
|
||||||
|
const relations : RelationFileInfo[] = relationXmlArray
|
||||||
|
.map(item => {
|
||||||
|
return {
|
||||||
|
id : this.parseRefId(item['_attr']['Id']),
|
||||||
|
type : schemeToType[item['_attr']['Type']],
|
||||||
|
targetFile : item['_attr']['Target']
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
.filter(item => item.type != null)
|
||||||
|
return relations;
|
||||||
|
}
|
||||||
|
|
||||||
|
extractDocumentRefs(xmlData : string) : DocumentRefs {
|
||||||
|
|
||||||
|
const xmlObj = fastXmlParser.parse(xmlData, parseOptions);
|
||||||
|
const sectionProp = xmlObj['w:document']['w:body']['w:sectPr'];
|
||||||
|
|
||||||
|
const headersXmlArray = Array.isArray(sectionProp['w:headerReference']) ? sectionProp['w:headerReference'] : [sectionProp['w:headerReference']];
|
||||||
|
const headers = headersXmlArray
|
||||||
|
.map(item => {
|
||||||
|
return {
|
||||||
|
type : item['_attr']['w:type'],
|
||||||
|
id : this.parseRefId(item['_attr']['r:id'])
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
const footersXmlArray = Array.isArray(sectionProp['w:footerReference']) ? sectionProp['w:footerReference'] : [sectionProp['w:footerReference']];
|
||||||
|
const footers = footersXmlArray
|
||||||
|
.map(item => {
|
||||||
|
return {
|
||||||
|
type : item['_attr']['w:type'],
|
||||||
|
id : this.parseRefId(item['_attr']['r:id'])
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {headers, footers}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseRefId(str : string) : number {
|
||||||
|
let match = /^rId(\d+)$/.exec(str);
|
||||||
|
if (match == null) {
|
||||||
|
throw 'invalid ref id';
|
||||||
|
}
|
||||||
|
return parseInt(match[1]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
Reference in New Issue
Block a user