From 2d8e70681551acbd093ac7168b0b5960fbabe494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Thu, 9 Feb 2023 14:05:31 +0800 Subject: [PATCH] feat: embed template xmls --- .gitignore | 2 + apidrawing.go | 7 + apirun.go | 16 -- apitext.go | 17 ++ cmd/getstructure/main.go | 3 +- cmd/main/main.go | 12 +- empty_constants.go | 389 -------------------------------------- files.go | 9 + pack.go | 40 ++-- structdoc_test.go | 26 ++- structnodes.go | 4 +- xml/[Content_Types].xml | 10 + xml/_rels/.rels | 6 + xml/docProps/app.xml | 1 + xml/docProps/core.xml | 1 + xml/word/styles.xml | 49 +++++ xml/word/theme/theme1.xml | 318 +++++++++++++++++++++++++++++++ 17 files changed, 481 insertions(+), 429 deletions(-) create mode 100644 apidrawing.go create mode 100644 apitext.go delete mode 100644 empty_constants.go create mode 100644 files.go create mode 100644 xml/[Content_Types].xml create mode 100644 xml/_rels/.rels create mode 100644 xml/docProps/app.xml create mode 100644 xml/docProps/core.xml create mode 100644 xml/word/styles.xml create mode 100644 xml/word/theme/theme1.xml diff --git a/.gitignore b/.gitignore index 70f0a4b..196db6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ docxlib .vscode/ +*.docx +/*.xml \ No newline at end of file diff --git a/apidrawing.go b/apidrawing.go new file mode 100644 index 0000000..bc8d3c4 --- /dev/null +++ b/apidrawing.go @@ -0,0 +1,7 @@ +package docxlib + +// AddDrawing adds drawing to paragraph +func (p *Paragraph) AddDrawing(pic []byte) *Run { + //TODO: finish add drawing + return nil +} diff --git a/apirun.go b/apirun.go index f7af38c..32e9627 100644 --- a/apirun.go +++ b/apirun.go @@ -17,19 +17,3 @@ func (r *Run) Size(size int) *Run { return r } - -// AddText adds text to paragraph -func (p *Paragraph) AddText(text string) *Run { - t := &Text{ - Text: text, - } - - run := &Run{ - Text: t, - RunProperties: &RunProperties{}, - } - - p.Children = append(p.Children, ParagraphChild{Run: run}) - - return run -} diff --git a/apitext.go b/apitext.go new file mode 100644 index 0000000..c556aa6 --- /dev/null +++ b/apitext.go @@ -0,0 +1,17 @@ +package docxlib + +// AddText adds text to paragraph +func (p *Paragraph) AddText(text string) *Run { + t := &Text{ + Text: text, + } + + run := &Run{ + Text: t, + RunProperties: &RunProperties{}, + } + + p.Children = append(p.Children, ParagraphChild{Run: run}) + + return run +} diff --git a/cmd/getstructure/main.go b/cmd/getstructure/main.go index a0c7c63..f491e1d 100644 --- a/cmd/getstructure/main.go +++ b/cmd/getstructure/main.go @@ -11,7 +11,7 @@ import ( var fileLocation *string func init() { - fileLocation = flag.String("file", "/tmp/new-file.docx", "file location") + fileLocation = flag.String("file", "new-file.docx", "file location") flag.Parse() } @@ -21,6 +21,7 @@ func main() { if err != nil { panic(err) } + defer readFile.Close() fileinfo, err := readFile.Stat() if err != nil { panic(err) diff --git a/cmd/main/main.go b/cmd/main/main.go index 538e425..1c2b27a 100644 --- a/cmd/main/main.go +++ b/cmd/main/main.go @@ -11,7 +11,7 @@ import ( var fileLocation *string func init() { - fileLocation = flag.String("file", "/tmp/new-file.docx", "file location") + fileLocation = flag.String("file", "new-file.docx", "file location") flag.Parse() } func main() { @@ -35,8 +35,14 @@ func main() { if err != nil { panic(err) } - defer f.Close() - w.Write(f) + err = w.Write(f) + if err != nil { + panic(err) + } + err = f.Close() + if err != nil { + panic(err) + } fmt.Println("Document writen. \nNow trying to read it") // Now let's try to read the file readFile, err := os.Open(*fileLocation) diff --git a/empty_constants.go b/empty_constants.go deleted file mode 100644 index ec8a94e..0000000 --- a/empty_constants.go +++ /dev/null @@ -1,389 +0,0 @@ -package docxlib - -const ( - TEMP_REL = ` - - - - - ` - TEMP_DOCPROPS_APP = `Go DOCX` - TEMP_DOCPROPS_CORE = `` - TEMP_CONTENT = ` - - - - - - - - - ` - TEMP_WORD_STYLE = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ` - TEMP_WORD_THEME_THEME = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ` -) diff --git a/files.go b/files.go new file mode 100644 index 0000000..4b09dac --- /dev/null +++ b/files.go @@ -0,0 +1,9 @@ +package docxlib + +import "embed" + +var ( + //go:embed xml + //go:embed xml/_rels/* + TEMP_XML_FS embed.FS +) diff --git a/pack.go b/pack.go index e48a4d6..6801db3 100644 --- a/pack.go +++ b/pack.go @@ -2,29 +2,37 @@ package docxlib import ( "archive/zip" + "bytes" "encoding/xml" - "strings" ) // This receives a zip file writer (word documents are a zip with multiple xml inside) // and writes the relevant files. Some of them come from the empty_constants file, // others from the actual in-memory structure func (f *Docx) pack(zipWriter *zip.Writer) (err error) { - files := map[string]string{} + fileslst := []string{ + "_rels/.rels", + "docProps/app.xml", + "docProps/core.xml", + "word/theme/theme1.xml", + "word/styles.xml", + "[Content_Types].xml", + } + files := make(map[string][]byte, 64) - files["_rels/.rels"] = TEMP_REL - files["docProps/app.xml"] = TEMP_DOCPROPS_APP - files["docProps/core.xml"] = TEMP_DOCPROPS_CORE - files["word/theme/theme1.xml"] = TEMP_WORD_THEME_THEME - files["word/styles.xml"] = TEMP_WORD_STYLE - files["[Content_Types].xml"] = TEMP_CONTENT + for _, name := range fileslst { + files[name], err = TEMP_XML_FS.ReadFile("xml/" + name) + if err != nil { + return + } + } files["word/_rels/document.xml.rels"], err = marshal(f.DocRelation) if err != nil { - return err + return } files["word/document.xml"], err = marshal(f.Document) if err != nil { - return err + return } for path, data := range files { @@ -33,7 +41,7 @@ func (f *Docx) pack(zipWriter *zip.Writer) (err error) { return err } - _, err = w.Write(StringToBytes(data)) + _, err = w.Write(data) if err != nil { return err } @@ -42,13 +50,13 @@ func (f *Docx) pack(zipWriter *zip.Writer) (err error) { return } -func marshal(data interface{}) (out string, err error) { - sb := strings.Builder{} - sb.WriteString(xml.Header) - err = xml.NewEncoder(&sb).Encode(data) +func marshal(data interface{}) (out []byte, err error) { + buf := bytes.NewBuffer(make([]byte, 0, 1024)) + buf.WriteString(xml.Header) + err = xml.NewEncoder(buf).Encode(data) if err != nil { return } - out = sb.String() + out = buf.Bytes() return } diff --git a/structdoc_test.go b/structdoc_test.go index 3cb1e68..1d8bb4e 100644 --- a/structdoc_test.go +++ b/structdoc_test.go @@ -2,13 +2,14 @@ package docxlib import ( "encoding/xml" + "os" "testing" ) const decoded_doc_1 = `testtest font sizetest colorNew style 1New style 2test font size and colorgoogle` const decoded_doc_2 = `Table of Contents TOC \h \z \t "Heading 1,2,S6,1,S0,1,S1,1,S2,1,S3,1,S4,1,S5,1" Holy Grail [xref:bRJduW6hNR] PAGEREF _Toc420414504 \h 21.What is your name? [xref:TH7u7QDqhD] PAGEREF _Toc420414505 \h 22.What is your quest? [xref:bC62HkFATC] PAGEREF _Toc420414506 \h 23.What is your favourite colour? [xref:I3TphuHX6N] PAGEREF _Toc420414507 \h 2Holy Grail [ FORMTEXT xref:bRJduW6hNR]What is your name? [ FORMTEXT xref:TH7u7QDqhD]My name is Sir Launcelot of Camelot.What is your quest? [ FORMTEXT xref:bC62HkFATC]To seek the Holy Grail[or a grail shaped beacon]. What is your favourite colour? [ FORMTEXT xref:I3TphuHX6N]Blue.How many paragraphs here then?` -func TestPlainStructure(t *testing.T) { +func TestUnmarshalPlainStructure(t *testing.T) { doc := Document{ XMLW: XMLNS_W, XMLR: XMLNS_R, @@ -512,7 +513,7 @@ const drawing_doc = ` ` -func TestDrawingStructure(t *testing.T) { +func TestUnmarshalDrawingStructure(t *testing.T) { doc := Document{ XMLW: XMLNS_W, XMLR: XMLNS_R, @@ -560,3 +561,24 @@ func TestDrawingStructure(t *testing.T) { } } } + +func TestMarshalDrawingStructure(t *testing.T) { + w := New() + // add new paragraph + para1 := w.AddParagraph() + // add text + para1.AddText("直接粘贴 inline") + + para2 := w.AddParagraph() + para2.AddText("test font size and color").Size(22).Color("ff0000") + + nextPara := w.AddParagraph() + nextPara.AddLink("google", `http://google.com`) + + doc, err := marshal(w.Document) + if err != nil { + t.Fatal(err) + } + os.WriteFile("test.xml", doc, 0644) + t.Fail() +} diff --git a/structnodes.go b/structnodes.go index 4b5a19b..a284032 100644 --- a/structnodes.go +++ b/structnodes.go @@ -12,8 +12,8 @@ type ParagraphChild struct { } type Paragraph struct { - XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main p"` - Children []ParagraphChild + XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main p"` + Children []ParagraphChild // Children will generate an unnecessary tag ... but we have no other choice file *Docx } diff --git a/xml/[Content_Types].xml b/xml/[Content_Types].xml new file mode 100644 index 0000000..64ddaa5 --- /dev/null +++ b/xml/[Content_Types].xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/xml/_rels/.rels b/xml/_rels/.rels new file mode 100644 index 0000000..f6210ee --- /dev/null +++ b/xml/_rels/.rels @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/xml/docProps/app.xml b/xml/docProps/app.xml new file mode 100644 index 0000000..ca90e47 --- /dev/null +++ b/xml/docProps/app.xml @@ -0,0 +1 @@ +Go DOCX \ No newline at end of file diff --git a/xml/docProps/core.xml b/xml/docProps/core.xml new file mode 100644 index 0000000..8b2abf2 --- /dev/null +++ b/xml/docProps/core.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/xml/word/styles.xml b/xml/word/styles.xml new file mode 100644 index 0000000..455516c --- /dev/null +++ b/xml/word/styles.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xml/word/theme/theme1.xml b/xml/word/theme/theme1.xml new file mode 100644 index 0000000..2bb59b7 --- /dev/null +++ b/xml/word/theme/theme1.xml @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file