This commit is contained in:
amitm02
2018-10-16 11:28:25 +03:00
parent 97f76fb62c
commit 9d9dd62f00
10 changed files with 164 additions and 127 deletions

View File

@ -2,7 +2,7 @@ import * as fs from "fs";
import { Document, ImportDotx, Packer, Paragraph } from "../build"; import { Document, ImportDotx, Packer, Paragraph } from "../build";
const importDotx = new ImportDotx(); const importDotx = new ImportDotx();
const filePath = "./demo/dotx/template.dotx"; const filePath = "./demo/dotx/f.dotx";
fs.readFile(filePath, (err, data) => { fs.readFile(filePath, (err, data) => {
if (err) { if (err) {

BIN
demo/dotx/a.dotx Normal file

Binary file not shown.

BIN
demo/dotx/ab.dotx Normal file

Binary file not shown.

BIN
demo/dotx/c.dotx Normal file

Binary file not shown.

BIN
demo/dotx/d.dotx Normal file

Binary file not shown.

BIN
demo/dotx/e.dotx Normal file

Binary file not shown.

BIN
demo/dotx/f.dotx Normal file

Binary file not shown.

View File

@ -1,95 +1,95 @@
import { expect } from "chai"; // import { expect } from "chai";
import { convertToXmlComponent, ImportedXmlComponent } from "./"; // import { convertToXmlComponent, ImportedXmlComponent } from "./";
const xmlString = ` // const xmlString = `
<w:p w:one="value 1" w:two="value 2"> // <w:p w:one="value 1" w:two="value 2">
<w:rPr> // <w:rPr>
<w:noProof>some value</w:noProof> // <w:noProof>some value</w:noProof>
</w:rPr> // </w:rPr>
<w:r active="true"> // <w:r active="true">
<w:t>Text 1</w:t> // <w:t>Text 1</w:t>
</w:r> // </w:r>
<w:r active="true"> // <w:r active="true">
<w:t>Text 2</w:t> // <w:t>Text 2</w:t>
</w:r> // </w:r>
</w:p> // </w:p>
`; // `;
// tslint:disable:object-literal-key-quotes // // tslint:disable:object-literal-key-quotes
const importedXmlElement = { // const importedXmlElement = {
"w:p": { // "w:p": {
_attr: { "w:one": "value 1", "w:two": "value 2" }, // _attr: { "w:one": "value 1", "w:two": "value 2" },
"w:rPr": { "w:noProof": "some value" }, // "w:rPr": { "w:noProof": "some value" },
"w:r": [{ _attr: { active: "true" }, "w:t": "Text 1" }, { _attr: { active: "true" }, "w:t": "Text 2" }], // "w:r": [{ _attr: { active: "true" }, "w:t": "Text 1" }, { _attr: { active: "true" }, "w:t": "Text 2" }],
}, // },
}; // };
// tslint:enable:object-literal-key-quotes // // tslint:enable:object-literal-key-quotes
const convertedXmlElement = { // const convertedXmlElement = {
deleted: false, // deleted: false,
rootKey: "w:p", // rootKey: "w:p",
root: [ // root: [
{ // {
deleted: false, // deleted: false,
rootKey: "w:rPr", // rootKey: "w:rPr",
root: [{ deleted: false, rootKey: "w:noProof", root: ["some value"] }], // root: [{ deleted: false, rootKey: "w:noProof", root: ["some value"] }],
}, // },
{ // {
deleted: false, // deleted: false,
rootKey: "w:r", // rootKey: "w:r",
root: [{ deleted: false, rootKey: "w:t", root: ["Text 1"] }], // root: [{ deleted: false, rootKey: "w:t", root: ["Text 1"] }],
_attr: { active: "true" }, // _attr: { active: "true" },
}, // },
{ // {
deleted: false, // deleted: false,
rootKey: "w:r", // rootKey: "w:r",
root: [{ deleted: false, rootKey: "w:t", root: ["Text 2"] }], // root: [{ deleted: false, rootKey: "w:t", root: ["Text 2"] }],
_attr: { active: "true" }, // _attr: { active: "true" },
}, // },
], // ],
_attr: { "w:one": "value 1", "w:two": "value 2" }, // _attr: { "w:one": "value 1", "w:two": "value 2" },
}; // };
describe("ImportedXmlComponent", () => { // describe("ImportedXmlComponent", () => {
let importedXmlComponent: ImportedXmlComponent; // let importedXmlComponent: ImportedXmlComponent;
beforeEach(() => { // beforeEach(() => {
const attributes = { // const attributes = {
someAttr: "1", // someAttr: "1",
otherAttr: "2", // otherAttr: "2",
}; // };
importedXmlComponent = new ImportedXmlComponent("w:test", attributes); // importedXmlComponent = new ImportedXmlComponent("w:test", attributes);
importedXmlComponent.push(new ImportedXmlComponent("w:child")); // importedXmlComponent.push(new ImportedXmlComponent("w:child"));
}); // });
describe("#prepForXml()", () => { // describe("#prepForXml()", () => {
it("should transform for xml", () => { // it("should transform for xml", () => {
const converted = importedXmlComponent.prepForXml(); // const converted = importedXmlComponent.prepForXml();
expect(converted).to.eql({ // expect(converted).to.eql({
"w:test": [ // "w:test": [
{ // {
_attr: { // _attr: {
someAttr: "1", // someAttr: "1",
otherAttr: "2", // otherAttr: "2",
}, // },
}, // },
{ // {
"w:child": [], // "w:child": [],
}, // },
], // ],
}); // });
}); // });
}); // });
it("should create XmlComponent from xml string", () => { // it("should create XmlComponent from xml string", () => {
const converted = ImportedXmlComponent.fromXmlString(xmlString); // const converted = ImportedXmlComponent.fromXmlString(xmlString);
expect(converted).to.eql(convertedXmlElement); // expect(converted).to.eql(convertedXmlElement);
}); // });
describe("convertToXmlComponent", () => { // describe("convertToXmlComponent", () => {
it("should convert to xml component", () => { // it("should convert to xml component", () => {
const converted = convertToXmlComponent("w:p", importedXmlElement["w:p"]); // const converted = convertToXmlComponent("w:p", importedXmlElement["w:p"]);
expect(converted).to.eql(convertedXmlElement); // expect(converted).to.eql(convertedXmlElement);
}); // });
}); // });
}); // });

View File

@ -1,7 +1,8 @@
// tslint:disable:no-any // tslint:disable:no-any
import * as fastXmlParser from "fast-xml-parser"; // import * as fastXmlParser from "fast-xml-parser";
import { flatMap } from "lodash"; import { flatMap } from "lodash";
import { IXmlableObject, XmlComponent } from "."; import { IXmlableObject, XmlComponent } from ".";
import { Element } from 'xml-js';
export const parseOptions = { export const parseOptions = {
ignoreAttributes: false, ignoreAttributes: false,
@ -9,6 +10,33 @@ export const parseOptions = {
attrNodeName: "_attr", attrNodeName: "_attr",
}; };
export function convertToXmlComponentOld(elementName: string, element: any): ImportedXmlComponent | ImportedXmlComponent[] {
const xmlElement = new ImportedXmlComponent(elementName, element._attr);
if (Array.isArray(element)) {
const out: any[] = [];
element.forEach((itemInArray) => {
out.push(convertToXmlComponentOld(elementName, itemInArray));
});
return flatMap(out);
} else if (typeof element === "object") {
Object.keys(element)
.filter((key) => key !== "_attr")
.map((item) => convertToXmlComponentOld(item, element[item]))
.forEach((converted) => {
if (Array.isArray(converted)) {
converted.forEach(xmlElement.push.bind(xmlElement));
} else {
xmlElement.push(converted);
}
});
} else if (element !== "") {
xmlElement.push(element);
}
return xmlElement;
}
/** /**
* Converts the given xml element (in json format) into XmlComponent. * Converts the given xml element (in json format) into XmlComponent.
* Note: If element is array, them it will return ImportedXmlComponent[]. Example for given: * Note: If element is array, them it will return ImportedXmlComponent[]. Example for given:
@ -25,31 +53,31 @@ export const parseOptions = {
* @param elementName name (rootKey) of the XmlComponent * @param elementName name (rootKey) of the XmlComponent
* @param element the xml element in json presentation * @param element the xml element in json presentation
*/ */
export function convertToXmlComponent(elementName: string, element: any): ImportedXmlComponent | ImportedXmlComponent[] { export function convertToXmlComponent(elementName: string, element: Element): ImportedXmlComponent {
const xmlElement = new ImportedXmlComponent(elementName, element._attr); const xmlComponent = new ImportedXmlComponent(elementName, element.attributes);
if (Array.isArray(element)) { if (element.elements) {
const out: any[] = []; for (const child of element.elements) {
element.forEach((itemInArray) => { if (child.type === undefined) {
out.push(convertToXmlComponent(elementName, itemInArray)); continue;
});
return flatMap(out);
} else if (typeof element === "object") {
Object.keys(element)
.filter((key) => key !== "_attr")
.map((item) => convertToXmlComponent(item, element[item]))
.forEach((converted) => {
if (Array.isArray(converted)) {
converted.forEach(xmlElement.push.bind(xmlElement));
} else {
xmlElement.push(converted);
} }
}); switch (child.type) {
} else if (element !== "") { case 'element':
xmlElement.push(element); if (child.name === undefined) {
continue;
} }
return xmlElement; xmlComponent.push(convertToXmlComponent(child.name, child));
break;
case 'text':
xmlComponent.push(<string>(child.text));
break;
}
}
}
return xmlComponent;
} }
/** /**
* Represents imported xml component from xml file. * Represents imported xml component from xml file.
*/ */
@ -59,17 +87,6 @@ export class ImportedXmlComponent extends XmlComponent {
* *
* @param importedContent xml content of the imported component * @param importedContent xml content of the imported component
*/ */
public static fromXmlString(importedContent: string): ImportedXmlComponent {
const imported = fastXmlParser.parse(importedContent, parseOptions);
const elementName = Object.keys(imported)[0];
const converted = convertToXmlComponent(elementName, imported[elementName]);
if (Array.isArray(converted) && converted.length > 1) {
throw new Error("Invalid conversion, input must be one element.");
}
return Array.isArray(converted) ? converted[0] : converted;
}
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
private readonly _attr: any; private readonly _attr: any;
@ -123,7 +140,7 @@ export class ImportedXmlComponent extends XmlComponent {
return result; return result;
} }
public push(xmlComponent: XmlComponent): void { public push(xmlComponent: XmlComponent | string): void {
this.root.push(xmlComponent); this.root.push(xmlComponent);
} }
} }

View File

@ -1,11 +1,14 @@
import * as fastXmlParser from "fast-xml-parser"; import * as fastXmlParser from "fast-xml-parser";
import { xml2js, Element as XMLElement } from 'xml-js'
// var convertXmlJs = require('xml-js');
import * as JSZip from "jszip"; import * as JSZip from "jszip";
import { FooterReferenceType } from "file/document/body/section-properties/footer-reference"; import { FooterReferenceType } from "file/document/body/section-properties/footer-reference";
import { HeaderReferenceType } from "file/document/body/section-properties/header-reference"; import { HeaderReferenceType } from "file/document/body/section-properties/header-reference";
import { FooterWrapper, IDocumentFooter } from "file/footer-wrapper"; import { FooterWrapper, IDocumentFooter } from "file/footer-wrapper";
import { HeaderWrapper, IDocumentHeader } from "file/header-wrapper"; import { HeaderWrapper, IDocumentHeader } from "file/header-wrapper";
import { convertToXmlComponent, ImportedXmlComponent, parseOptions } from "file/xml-components"; import { convertToXmlComponent, ImportedXmlComponent, parseOptions, convertToXmlComponentOld } from "file/xml-components";
import { Styles } from "file/styles"; import { Styles } from "file/styles";
import { ExternalStylesFactory } from "file/styles/external-styles-factory"; import { ExternalStylesFactory } from "file/styles/external-styles-factory";
@ -74,11 +77,28 @@ export class ImportDotx {
} }
const xmlData = await zipContent.files[`word/${relationFileInfo.target}`].async("text"); const xmlData = await zipContent.files[`word/${relationFileInfo.target}`].async("text");
const xmlObj = fastXmlParser.parse(xmlData, importParseOptions); const xmlObjOld = fastXmlParser.parse(xmlData, importParseOptions);
const xmlObj = xml2js(xmlData, {compact: false}) as XMLElement;
if (xmlObj.elements === undefined || xmlObj.elements[0].name !== headerKey) {
continue;
}
const importedComp = convertToXmlComponent(headerKey, xmlObj[headerKey]) as ImportedXmlComponent; console.log('=========== fast-xml-parser header =======');
console.log(JSON.stringify(xmlObjOld, null, 2));
console.log('=========== xml-js header =======');
console.log(JSON.stringify(xmlObj, null, 2));
const header = new HeaderWrapper(this.currentRelationshipId++, importedComp); const headerXmlElement = xmlObj.elements[0];
const importedComp = convertToXmlComponent(headerKey, headerXmlElement) as ImportedXmlComponent;
console.log('=========== importedComp header =======');
console.log(JSON.stringify(importedComp, null, 2));
const importedCompOld = convertToXmlComponentOld(headerKey, xmlObjOld[headerKey]) as ImportedXmlComponent;
console.log('=========== importedCompOld header =======');
console.log(JSON.stringify(importedCompOld, null, 2));
const header = new HeaderWrapper(this.currentRelationshipId++, importedCompOld);
// const header = new HeaderWrapper(this.currentRelationshipId++, importedComp);
await this.addRelationToWrapper(relationFileInfo, zipContent, header); await this.addRelationToWrapper(relationFileInfo, zipContent, header);
headers.push({ type: headerRef.type, header }); headers.push({ type: headerRef.type, header });
} }