mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
document: add more documentation and examples
This commit is contained in:
parent
3820294523
commit
caebe001a8
@ -16,7 +16,7 @@ func main() {
|
||||
|
||||
// FindAllFields is a helper function that traverses the document
|
||||
// identifying fields
|
||||
fields := document.FindAllFields(doc)
|
||||
fields := doc.FormFields()
|
||||
fmt.Println("found", len(fields), "fields")
|
||||
|
||||
for _, fld := range fields {
|
||||
|
3
doc.go
3
doc.go
@ -22,5 +22,8 @@ spreadsheet.Workbook and presentation.Presentation), the other wrapper types are
|
||||
value types with non-pointer methods. They exist solely to modify and return
|
||||
data from one or more XML types.
|
||||
|
||||
The packages of interest are baliance.com/gooxml/document,
|
||||
baliance/gooxml/spreadsheet and baliance.com/gooxml/presentation.
|
||||
|
||||
*/
|
||||
package gooxml
|
||||
|
@ -27,7 +27,9 @@ import (
|
||||
"baliance.com/gooxml/zippkg"
|
||||
)
|
||||
|
||||
// Document is a text document that can be written out in the OOXML .docx format.
|
||||
// Document is a text document that can be written out in the OOXML .docx
|
||||
// format. It can be opened from a file on disk and modified, or created from
|
||||
// scratch.
|
||||
type Document struct {
|
||||
common.DocBase
|
||||
x *wml.Document
|
||||
@ -89,7 +91,8 @@ func (d *Document) X() *wml.Document {
|
||||
return d.x
|
||||
}
|
||||
|
||||
// AddHeader creates a header, but doesn't add it to the document for display.
|
||||
// AddHeader creates a header associated with the document, but doesn't add it
|
||||
// to the document for display.
|
||||
func (d *Document) AddHeader() Header {
|
||||
hdr := wml.NewHdr()
|
||||
d.headers = append(d.headers, hdr)
|
||||
@ -100,7 +103,8 @@ func (d *Document) AddHeader() Header {
|
||||
return Header{d, hdr}
|
||||
}
|
||||
|
||||
// AddFooter creates a Footer, but doesn't add it to the document for display.
|
||||
// AddFooter creates a Footer associated with the document, but doesn't add it
|
||||
// to the document for display.
|
||||
func (d *Document) AddFooter() Footer {
|
||||
ftr := wml.NewFtr()
|
||||
d.footers = append(d.footers, ftr)
|
||||
@ -111,8 +115,8 @@ func (d *Document) AddFooter() Footer {
|
||||
}
|
||||
|
||||
// BodySection returns the default body section used for all preceeding
|
||||
// paragraphs until the previous Section. If there is no previous section, it
|
||||
// applies to the entire document.
|
||||
// paragraphs until the previous Section. If there is no previous sections, the
|
||||
// body section applies to the entire document.
|
||||
func (d *Document) BodySection() Section {
|
||||
if d.x.Body.SectPr == nil {
|
||||
d.x.Body.SectPr = wml.NewCT_SectPr()
|
||||
@ -285,7 +289,7 @@ func Open(filename string) (*Document, error) {
|
||||
// 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
|
||||
// opened with OpenTemplate the document's styles will be available but the
|
||||
// content will be gone.
|
||||
func OpenTemplate(filename string) (*Document, error) {
|
||||
d, err := Open(filename)
|
||||
@ -449,7 +453,9 @@ func Read(r io.ReaderAt, size int64) (*Document, error) {
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
// Validate attempts to validate the structure of a document.
|
||||
// Validate validates the structure and in cases where it't possible, the ranges
|
||||
// of elements within a document. A validation error dones't mean that the
|
||||
// document won't work in MS Word or LibreOffice, but it's worth checking into.
|
||||
func (d *Document) Validate() error {
|
||||
if d == nil || d.x == nil {
|
||||
return errors.New("document not initialized correctly, nil base")
|
||||
@ -518,3 +524,54 @@ func (d *Document) Images() []ImageRef {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// FormFields extracts all of the fields from a document. They can then be
|
||||
// manipulated via the methods on the field and the document saved.
|
||||
func (d *Document) FormFields() []FormField {
|
||||
ret := []FormField{}
|
||||
for _, p := range d.Paragraphs() {
|
||||
runs := p.Runs()
|
||||
for i, r := range runs {
|
||||
for _, ic := range r.x.EG_RunInnerContent {
|
||||
// skip non form fields
|
||||
if ic.FldChar == nil || ic.FldChar.FfData == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// found a begin form field
|
||||
if ic.FldChar.FldCharTypeAttr == wml.ST_FldCharTypeBegin {
|
||||
// ensure it has a name
|
||||
if len(ic.FldChar.FfData.Name) == 0 || ic.FldChar.FfData.Name[0].ValAttr == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
field := FormField{x: ic.FldChar.FfData}
|
||||
// for text input boxes, we need a pointer to where to set
|
||||
// the text as well
|
||||
if ic.FldChar.FfData.TextInput != nil {
|
||||
|
||||
// ensure we always have at lest two IC's
|
||||
for j := i + 1; j < len(runs)-1; j++ {
|
||||
if len(runs[j].x.EG_RunInnerContent) == 0 {
|
||||
continue
|
||||
}
|
||||
ic := runs[j].x.EG_RunInnerContent[0]
|
||||
// look for the 'separate' field
|
||||
if ic.FldChar != nil && ic.FldChar.FldCharTypeAttr == wml.ST_FldCharTypeSeparate {
|
||||
if len(runs[j+1].x.EG_RunInnerContent) == 0 {
|
||||
continue
|
||||
}
|
||||
// the value should be the text in the next inner content that is not a field char
|
||||
if runs[j+1].x.EG_RunInnerContent[0].FldChar == nil {
|
||||
field.textIC = runs[j+1].x.EG_RunInnerContent[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = append(ret, field)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
66
document/document_examples_test.go
Normal file
66
document/document_examples_test.go
Normal file
@ -0,0 +1,66 @@
|
||||
package document_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"baliance.com/gooxml/document"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
doc := document.New()
|
||||
doc.AddParagraph().AddRun().AddText("Hello World!")
|
||||
doc.SaveToFile("document.docx")
|
||||
}
|
||||
|
||||
func ExampleOpen() {
|
||||
doc, err := document.Open("existing.docx")
|
||||
if err != nil {
|
||||
log.Fatalf("error opening document: %s", err)
|
||||
}
|
||||
for _, para := range doc.Paragraphs() {
|
||||
for _, run := range para.Runs() {
|
||||
fmt.Print(run.Text())
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleOpenTemplate() {
|
||||
doc, err := document.OpenTemplate("existing.docx")
|
||||
if err != nil {
|
||||
log.Fatalf("error opening document template: %s", err)
|
||||
}
|
||||
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")
|
||||
doc.SaveToFile("ouput.docx")
|
||||
}
|
||||
|
||||
func ExampleDocument_FormFields() {
|
||||
doc, err := document.Open("invitation.docx")
|
||||
if err != nil {
|
||||
log.Fatalf("error opening document form: %s", err)
|
||||
}
|
||||
for _, field := range doc.FormFields() {
|
||||
switch field.Name() {
|
||||
case "attendingEvent":
|
||||
if field.Type() == document.FormFieldTypeCheckBox {
|
||||
field.SetChecked(true)
|
||||
}
|
||||
case "name":
|
||||
if field.Type() == document.FormFieldTypeText {
|
||||
field.SetValue("John Smith")
|
||||
}
|
||||
}
|
||||
}
|
||||
doc.SaveToFile("invitation-respoonse.docx")
|
||||
}
|
@ -23,8 +23,8 @@ const (
|
||||
FormFieldTypeDropDown
|
||||
)
|
||||
|
||||
// FormField is a form within a document. It references the document, so
|
||||
// changes to the form field wil be reflected in the document if it is saved.
|
||||
// FormField is a form within a document. It references the document, so changes
|
||||
// to the form field wil be reflected in the document if it is saved.
|
||||
type FormField struct {
|
||||
x *wml.CT_FFData
|
||||
textIC *wml.EG_RunInnerContent
|
||||
@ -121,54 +121,3 @@ func (f FormField) SetChecked(b bool) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// FindAllFields extracts all of the fields from a document. They can then be
|
||||
// manipulated via the methods on the field and the document can be saved.
|
||||
func FindAllFields(d *Document) []FormField {
|
||||
ret := []FormField{}
|
||||
for _, p := range d.Paragraphs() {
|
||||
runs := p.Runs()
|
||||
for i, r := range runs {
|
||||
for _, ic := range r.x.EG_RunInnerContent {
|
||||
// skip non form fields
|
||||
if ic.FldChar == nil || ic.FldChar.FfData == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// found a begin form field
|
||||
if ic.FldChar.FldCharTypeAttr == wml.ST_FldCharTypeBegin {
|
||||
// ensure it has a name
|
||||
if len(ic.FldChar.FfData.Name) == 0 || ic.FldChar.FfData.Name[0].ValAttr == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
field := FormField{x: ic.FldChar.FfData}
|
||||
// for text input boxes, we need a pointer to where to set
|
||||
// the text as well
|
||||
if ic.FldChar.FfData.TextInput != nil {
|
||||
|
||||
// ensure we always have at lest two IC's
|
||||
for j := i + 1; j < len(runs)-1; j++ {
|
||||
if len(runs[j].x.EG_RunInnerContent) == 0 {
|
||||
continue
|
||||
}
|
||||
ic := runs[j].x.EG_RunInnerContent[0]
|
||||
// look for the 'separate' field
|
||||
if ic.FldChar != nil && ic.FldChar.FldCharTypeAttr == wml.ST_FldCharTypeSeparate {
|
||||
if len(runs[j+1].x.EG_RunInnerContent) == 0 {
|
||||
continue
|
||||
}
|
||||
// the value should be the text in the next inner content that is not a field char
|
||||
if runs[j+1].x.EG_RunInnerContent[0].FldChar == nil {
|
||||
field.textIC = runs[j+1].x.EG_RunInnerContent[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = append(ret, field)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
11
example_test.go
Normal file
11
example_test.go
Normal file
@ -0,0 +1,11 @@
|
||||
package gooxml_test
|
||||
|
||||
import "baliance.com/gooxml/document"
|
||||
|
||||
func Example_document() {
|
||||
// see the baliance.com/gooxml/document documentation or _examples/document
|
||||
// for more examples
|
||||
doc := document.New()
|
||||
doc.AddParagraph().AddRun().AddText("Hello World!")
|
||||
doc.SaveToFile("document.docx")
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user