styles: support for external styles. parsing external styles.

This commit is contained in:
Igor Bulovski
2018-03-28 14:54:07 +02:00
parent d293ae516c
commit 5242f7d55c
11 changed files with 345 additions and 17 deletions

View File

@ -0,0 +1,147 @@
import { expect } from "chai";
import { ExternalStylesFactory } from "./external-styles-factory";
describe("External styles factory", () => {
let externalStyles;
beforeEach(() => {
externalStyles = `
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:styles xmlns:mc="first" xmlns:r="second">
<w:docDefaults>
</w:docDefaults>
<w:latentStyles w:defLockedState="1" w:defUIPriority="99">
</w:latentStyles>
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
<w:name w:val="Normal"/>
<w:qFormat/>
</w:style>
<w:style w:type="paragraph" w:styleId="Heading1">
<w:name w:val="heading 1"/>
<w:basedOn w:val="Normal"/>
<w:pPr>
<w:keepNext/>
<w:keepLines/>
<w:pBdr>
<w:bottom w:val="single" w:sz="4" w:space="1" w:color="auto"/>
</w:pBdr>
</w:pPr>
</w:style>
</w:styles>`;
});
describe("#parse", () => {
it("should parse w:styles attributes", () => {
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
expect(importedStyle.rootKey).to.equal("w:styles");
expect(importedStyle.root[0]._attr).to.eql({
"xmlns:mc": "first",
"xmlns:r": "second",
});
});
it("should parse other child elements of w:styles", () => {
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
expect(importedStyle.root.length).to.equal(5);
expect(importedStyle.root[1]).to.eql({
root: [],
rootKey: "w:docDefaults",
});
expect(importedStyle.root[2]).to.eql({
_attr: {
"w:defLockedState": "1",
"w:defUIPriority": "99",
},
root: [],
rootKey: "w:latentStyles",
});
});
it("should parse styles elements", () => {
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
expect(importedStyle.root.length).to.equal(5);
expect(importedStyle.root[3]).to.eql({
_attr: {
"w:default": "1",
"w:styleId": "Normal",
"w:type": "paragraph",
},
root: [
{
_attr: {
"w:val": "Normal",
},
root: [],
rootKey: "w:name",
},
{
root: [],
rootKey: "w:qFormat",
},
],
rootKey: "w:style",
});
expect(importedStyle.root[4]).to.eql({
_attr: {
"w:styleId": "Heading1",
"w:type": "paragraph",
},
root: [
{
_attr: {
"w:val": "heading 1",
},
root: [],
rootKey: "w:name",
},
{
_attr: {
"w:val": "Normal",
},
root: [],
rootKey: "w:basedOn",
},
{
root: [
{
root: [],
rootKey: "w:keepNext",
},
{
root: [],
rootKey: "w:keepLines",
},
{
root: [
{
_attr: {
"w:color": "auto",
"w:space": "1",
"w:sz": "4",
"w:val": "single",
},
root: [],
rootKey: "w:bottom",
},
],
rootKey: "w:pBdr",
},
],
rootKey: "w:pPr",
},
],
rootKey: "w:style",
});
});
});
});

View File

@ -0,0 +1,64 @@
import { Styles } from "./";
import * as fastXmlParser from "fast-xml-parser";
import { ImportedXmlComponent, ImportedRootElementAttributes } from "./../../file/xml-components";
const parseOptions = {
ignoreAttributes: false,
attributeNamePrefix: "",
attrNodeName: "_attr",
};
export class ExternalStylesFactory {
/**
* Creates new Style based on the given styles.
* Parses the styles and convert them to XmlComponent.
* Example content from styles.xml:
* <?xml version="1.0">
* <w:styles xmlns:mc="some schema" ...>
*
* <w:style w:type="paragraph" w:styleId="Heading1">
* <w:name w:val="heading 1"/>
* .....
* </w:style>
*
* <w:style w:type="paragraph" w:styleId="Heading2">
* <w:name w:val="heading 2"/>
* .....
* </w:style>
*
* <w:docDefaults>Or any other element will be parsed to</w:docDefaults>
*
* </w:styles>
* @param externalStyles context from styles.xml
*/
public newInstance(externalStyles: string): Styles {
const xmlStyles = fastXmlParser.parse(externalStyles, parseOptions)["w:styles"];
// create styles with attributes from the parsed xml
const importedStyle = new Styles(new ImportedRootElementAttributes(xmlStyles._attr));
// convert other elements (not styles definitions, but default styles and so on ...)
Object.keys(xmlStyles)
.filter((element) => element !== "_attr" && element !== "w:style")
.forEach((element) => {
importedStyle.push(new ImportedXmlComponent(element, xmlStyles[element]._attr));
});
// convert the styles one by one
xmlStyles["w:style"]
.map((style) => this.convertElement("w:style", style))
.forEach(importedStyle.push.bind(importedStyle));
return importedStyle;
}
convertElement(elementName: string, element: any): ImportedXmlComponent {
const xmlElement = new ImportedXmlComponent(elementName, element._attr);
if (typeof element === "object") {
Object.keys(element)
.filter((key) => key !== "_attr")
.map((item) => this.convertElement(item, element[item]))
.forEach(xmlElement.push.bind(xmlElement));
}
return xmlElement;
}
}

View File

@ -1,7 +1,8 @@
import { Color, Italics, Size } from "../paragraph/run/formatting";
import { Styles } from "./";
// import { DocumentDefaults } from "./defaults";
import { DocumentAttributes } from "../document/document-attributes";
import {
Heading1Style,
Heading2Style,
@ -15,7 +16,15 @@ import {
export class DefaultStylesFactory {
public newInstance(): Styles {
const styles = new Styles();
const documentAttributes = new DocumentAttributes({
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
Ignorable: "w14 w15",
});
const styles = new Styles(documentAttributes);
styles.createDocumentDefaults();
const titleStyle = new TitleStyle();

View File

@ -1,21 +1,13 @@
import { XmlComponent } from "file/xml-components";
import { DocumentAttributes } from "../document/document-attributes";
import { XmlComponent, BaseXmlComponent } from "file/xml-components";
import { DocumentDefaults } from "./defaults";
import { ParagraphStyle } from "./style";
export class Styles extends XmlComponent {
constructor() {
constructor(_initialStyles?: BaseXmlComponent) {
super("w:styles");
this.root.push(
new DocumentAttributes({
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
Ignorable: "w14 w15",
}),
);
if (_initialStyles) {
this.root.push(_initialStyles);
}
}
public push(style: XmlComponent): Styles {