mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-27 13:48:54 +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())
|
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.
|
// Read reads a document from an io.Reader.
|
||||||
func Read(r io.ReaderAt, size int64) (*Document, error) {
|
func Read(r io.ReaderAt, size int64) (*Document, error) {
|
||||||
doc := New()
|
doc := New()
|
||||||
|
@ -21,6 +21,11 @@ func (s Style) X() *wml.CT_Style {
|
|||||||
return s.x
|
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.
|
// StyleID returns the style ID.
|
||||||
func (s Style) StyleID() string {
|
func (s Style) StyleID() string {
|
||||||
if s.x.StyleIdAttr == nil {
|
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.LineAttr.Int32 = gooxml.Int32(259)
|
||||||
s.x.DocDefaults.PPrDefault.PPr.Spacing.LineRuleAttr = wml.ST_LineSpacingRuleAuto
|
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"
|
"baliance.com/gooxml/zippkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWtyleSheetUnmarshal(t *testing.T) {
|
func TestStyleSheetUnmarshal(t *testing.T) {
|
||||||
f, err := os.Open("testdata/styles.xml")
|
f, err := os.Open("testdata/styles.xml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error reading content types file")
|
t.Fatalf("error reading content types file")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user