mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
examples: add Word template example
Add an example that shows how to use a Word document as a template and pull its styles for use in a new document.
This commit is contained in:
parent
9237920cf3
commit
8e630657bf
56
_examples/document/use-template/main.go
Normal file
56
_examples/document/use-template/main.go
Normal file
@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"baliance.com/gooxml/document"
|
||||
)
|
||||
|
||||
var lorem = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin lobortis, lectus dictum feugiat tempus, sem neque finibus enim, sed eleifend sem nunc ac diam. Vestibulum tempus sagittis elementum`
|
||||
|
||||
func main() {
|
||||
// When Word saves a document, it removes all unused styles. This means to
|
||||
// copy the styles from an existing document, you must first create a
|
||||
// document that contains text in each style of interest. As an example,
|
||||
// see the template.docx in this directory. It contains a paragraph set in
|
||||
// each style that Word supports by default.
|
||||
doc, err := document.OpenTemplate("template.docx")
|
||||
if err != nil {
|
||||
log.Fatalf("error opening Windows Word 2016 document: %s", err)
|
||||
}
|
||||
|
||||
// We can now print out all styles in the document, verifying that they
|
||||
// exist.
|
||||
for _, s := range doc.Styles.ParagraphStyles() {
|
||||
fmt.Println("style", s.Name(), "has ID of", s.StyleID())
|
||||
}
|
||||
|
||||
// And create documents setting their style to the style ID (not style name).
|
||||
para := doc.AddParagraph()
|
||||
para.SetStyle("Title")
|
||||
para.AddRun().AddText("My Document Title")
|
||||
|
||||
para = doc.AddParagraph()
|
||||
para.SetStyle("Subtitle")
|
||||
para.AddRun().AddText("Document Subtitle")
|
||||
|
||||
para = doc.AddParagraph()
|
||||
para.SetStyle("Heading1")
|
||||
para.AddRun().AddText("Major Section")
|
||||
para = doc.AddParagraph()
|
||||
para = doc.AddParagraph()
|
||||
for i := 0; i < 4; i++ {
|
||||
para.AddRun().AddText(lorem)
|
||||
}
|
||||
|
||||
para = doc.AddParagraph()
|
||||
para.SetStyle("Heading2")
|
||||
para.AddRun().AddText("Minor Section")
|
||||
para = doc.AddParagraph()
|
||||
for i := 0; i < 4; i++ {
|
||||
para.AddRun().AddText(lorem)
|
||||
}
|
||||
|
||||
doc.SaveToFile("use-template.docx")
|
||||
}
|
BIN
_examples/document/use-template/template.docx
Normal file
BIN
_examples/document/use-template/template.docx
Normal file
Binary file not shown.
BIN
_examples/document/use-template/use-template.docx
Normal file
BIN
_examples/document/use-template/use-template.docx
Normal file
Binary file not shown.
@ -272,6 +272,20 @@ func Open(filename string) (*Document, error) {
|
||||
return Read(f, fi.Size())
|
||||
}
|
||||
|
||||
// OpenTemplate opens a document, removing all content so it can be used as a
|
||||
// template. Since Word removes unused styles from a document upon save, to
|
||||
// create a template in Word add a paragraph with every style of interest. When
|
||||
// opened with OpenTemplate the documents styles will be available but the
|
||||
// content will be gone.
|
||||
func OpenTemplate(filename string) (*Document, error) {
|
||||
d, err := Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.x.Body = wml.NewCT_Body()
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// Read reads a document from an io.Reader.
|
||||
func Read(r io.ReaderAt, size int64) (*Document, error) {
|
||||
doc := New()
|
||||
|
@ -21,6 +21,11 @@ func (s Style) X() *wml.CT_Style {
|
||||
return s.x
|
||||
}
|
||||
|
||||
// Type returns the type of the style.
|
||||
func (s Style) Type() wml.ST_StyleType {
|
||||
return s.x.TypeAttr
|
||||
}
|
||||
|
||||
// StyleID returns the style ID.
|
||||
func (s Style) StyleID() string {
|
||||
if s.x.StyleIdAttr == nil {
|
||||
|
@ -206,3 +206,24 @@ func (s Styles) initializeDocDefaults() {
|
||||
s.x.DocDefaults.PPrDefault.PPr.Spacing.LineAttr.Int32 = gooxml.Int32(259)
|
||||
s.x.DocDefaults.PPrDefault.PPr.Spacing.LineRuleAttr = wml.ST_LineSpacingRuleAuto
|
||||
}
|
||||
|
||||
// Styles returns all styles.
|
||||
func (s Styles) Styles() []Style {
|
||||
ret := []Style{}
|
||||
for _, s := range s.x.Style {
|
||||
ret = append(ret, Style{s})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Styles returns only paragraph styles.
|
||||
func (s Styles) ParagraphStyles() []Style {
|
||||
ret := []Style{}
|
||||
for _, s := range s.x.Style {
|
||||
if s.TypeAttr != wml.ST_StyleTypeParagraph {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, Style{s})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
64
document/styles_test.go
Normal file
64
document/styles_test.go
Normal file
@ -0,0 +1,64 @@
|
||||
package document_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"baliance.com/gooxml/document"
|
||||
"baliance.com/gooxml/testhelper"
|
||||
"baliance.com/gooxml/zippkg"
|
||||
)
|
||||
|
||||
func TestStylesUnmarshal(t *testing.T) {
|
||||
f, err := os.Open("testdata/styles.xml")
|
||||
if err != nil {
|
||||
t.Fatalf("error reading content types file")
|
||||
}
|
||||
defer f.Close()
|
||||
dec := xml.NewDecoder(f)
|
||||
r := document.NewStyles()
|
||||
if err := dec.Decode(r.X()); err != nil {
|
||||
t.Errorf("error decoding content types: %s", err)
|
||||
}
|
||||
got := &bytes.Buffer{}
|
||||
fmt.Fprintf(got, zippkg.XMLHeader)
|
||||
enc := xml.NewEncoder(zippkg.SelfClosingWriter{W: got})
|
||||
if err := enc.Encode(r.X()); err != nil {
|
||||
t.Errorf("error encoding content types: %s", err)
|
||||
}
|
||||
|
||||
testhelper.CompareGoldenXML(t, "styles.xml", got.Bytes())
|
||||
}
|
||||
|
||||
func TestStylesList(t *testing.T) {
|
||||
f, err := os.Open("testdata/styles.xml")
|
||||
if err != nil {
|
||||
t.Fatalf("error reading content types file")
|
||||
}
|
||||
defer f.Close()
|
||||
dec := xml.NewDecoder(f)
|
||||
r := document.NewStyles()
|
||||
if err := dec.Decode(r.X()); err != nil {
|
||||
t.Errorf("error decoding content types: %s", err)
|
||||
}
|
||||
expStyleCnt := 26
|
||||
if got := len(r.Styles()); got != expStyleCnt {
|
||||
t.Errorf("expected %d total styles, got %d", expStyleCnt, got)
|
||||
}
|
||||
|
||||
expParaStyleCnt := 9
|
||||
if got := len(r.ParagraphStyles()); got != expParaStyleCnt {
|
||||
t.Errorf("expected %d total paragraph styles, got %d", expStyleCnt, got)
|
||||
}
|
||||
for _, ps := range r.ParagraphStyles() {
|
||||
switch ps.StyleID() {
|
||||
case "Normal", "Heading1", "Heading2", "Heading3",
|
||||
"Title", "Subtitle", "Quote", "IntenseQuote", "ListParagraph":
|
||||
default:
|
||||
t.Errorf("unexpected paragraph style: %s", ps.StyleID())
|
||||
}
|
||||
}
|
||||
}
|
2
document/testdata/styles.xml
vendored
Normal file
2
document/testdata/styles.xml
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -19,7 +19,7 @@ import (
|
||||
"baliance.com/gooxml/zippkg"
|
||||
)
|
||||
|
||||
func TestWtyleSheetUnmarshal(t *testing.T) {
|
||||
func TestStyleSheetUnmarshal(t *testing.T) {
|
||||
f, err := os.Open("testdata/styles.xml")
|
||||
if err != nil {
|
||||
t.Fatalf("error reading content types file")
|
||||
|
Loading…
x
Reference in New Issue
Block a user