1
0
mirror of https://github.com/fumiama/go-docx.git synced 2026-06-10 18:40:28 +08:00

refactor: Run use Children

This commit is contained in:
源文雨
2023-02-25 21:18:29 +08:00
parent e32b907c6a
commit fafd4c9fc3
14 changed files with 101 additions and 129 deletions

View File

@@ -99,9 +99,11 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) {
}, },
}, },
} }
c := make([]interface{}, 1, 64)
c[0] = d
run := &Run{ run := &Run{
Drawing: d,
RunProperties: &RunProperties{}, RunProperties: &RunProperties{},
Children: c,
} }
p.Children = append(p.Children, run) p.Children = append(p.Children, run)
return run, nil return run, nil
@@ -207,9 +209,11 @@ func (p *Paragraph) AddAnchorDrawing(pic []byte) (*Run, error) {
}, },
}, },
} }
c := make([]interface{}, 1, 64)
c[0] = d
run := &Run{ run := &Run{
Drawing: d,
RunProperties: &RunProperties{}, RunProperties: &RunProperties{},
Children: c,
} }
p.Children = append(p.Children, run) p.Children = append(p.Children, run)
return run, nil return run, nil

View File

@@ -24,8 +24,6 @@ import "unsafe"
// AddParagraph adds a new paragraph // AddParagraph adds a new paragraph
func (f *Docx) AddParagraph() *Paragraph { func (f *Docx) AddParagraph() *Paragraph {
f.Document.Body.mu.Lock()
defer f.Document.Body.mu.Unlock()
f.Document.Body.Items = append(f.Document.Body.Items, Paragraph{ f.Document.Body.Items = append(f.Document.Body.Items, Paragraph{
Children: make([]interface{}, 0, 64), Children: make([]interface{}, 0, 64),
file: f, file: f,
@@ -38,9 +36,6 @@ func (f *Docx) AddParagraph() *Paragraph {
// AddParagraph adds a new paragraph // AddParagraph adds a new paragraph
func (c *WTableCell) AddParagraph() *Paragraph { func (c *WTableCell) AddParagraph() *Paragraph {
c.mu.Lock()
defer c.mu.Unlock()
c.Paragraphs = append(c.Paragraphs, Paragraph{ c.Paragraphs = append(c.Paragraphs, Paragraph{
Children: make([]interface{}, 0, 64), Children: make([]interface{}, 0, 64),
file: c.file, file: c.file,

View File

@@ -20,8 +20,6 @@
package docxlib package docxlib
import "encoding/xml"
// Color allows to set run color // Color allows to set run color
func (r *Run) Color(color string) *Run { func (r *Run) Color(color string) *Run {
r.RunProperties.Color = &Color{ r.RunProperties.Color = &Color{
@@ -42,16 +40,6 @@ func (r *Run) Size(size string) *Run {
// AddTab add a tab in front of the run // AddTab add a tab in front of the run
func (r *Run) AddTab() *Run { func (r *Run) AddTab() *Run {
r.FrontTab = append(r.FrontTab, struct { r.Children = append(r.Children, &WTab{})
XMLName xml.Name "xml:\"w:tab,omitempty\""
}{})
return r
}
// AppendTab add a tab after the run
func (r *Run) AppendTab() *Run {
r.RearTab = append(r.RearTab, struct {
XMLName xml.Name "xml:\"w:tab,omitempty\""
}{})
return r return r
} }

View File

@@ -42,8 +42,6 @@ func (f *Docx) AddTable(row int, col int) *WTable {
TableCells: cells, TableCells: cells,
} }
} }
f.Document.Body.mu.Lock()
defer f.Document.Body.mu.Unlock()
f.Document.Body.Items = append(f.Document.Body.Items, WTable{ f.Document.Body.Items = append(f.Document.Body.Items, WTable{
TableProperties: &WTableProperties{ TableProperties: &WTableProperties{
Width: &WTableWidth{Type: "auto"}, Width: &WTableWidth{Type: "auto"},
@@ -101,8 +99,6 @@ func (f *Docx) AddTableTwips(rowHeights []int64, colWidths []int64) *WTable {
} }
} }
} }
f.Document.Body.mu.Lock()
defer f.Document.Body.mu.Unlock()
f.Document.Body.Items = append(f.Document.Body.Items, WTable{ f.Document.Body.Items = append(f.Document.Body.Items, WTable{
TableProperties: &WTableProperties{ TableProperties: &WTableProperties{
Width: &WTableWidth{Type: "auto"}, Width: &WTableWidth{Type: "auto"},

View File

@@ -20,17 +20,20 @@
package docxlib package docxlib
import "encoding/xml" import "strings"
// AddTab adds tab to para // AddTab adds tab to para
func (p *Paragraph) AddTab() *Run { func (p *Paragraph) AddTab() *Run {
c := make([]interface{}, 1, 64)
c[0] = &WTab{}
run := &Run{ run := &Run{
RunProperties: &RunProperties{}, RunProperties: &RunProperties{},
FrontTab: []struct { Children: c,
XMLName xml.Name "xml:\"w:tab,omitempty\""
}{{}},
} }
p.Children = append(p.Children, run) p.Children = append(p.Children, run)
return run return run
} }
@@ -40,13 +43,22 @@ func (p *Paragraph) AddText(text string) *Run {
return p.AddTab() return p.AddTab()
} }
t := &Text{ c := make([]interface{}, 0, 64)
Text: text,
for i, s := range strings.Split(text, "\t") {
if i > 0 {
c = append(c, &WTab{})
}
if s != "" {
c = append(c, &Text{
Text: s,
})
}
} }
run := &Run{ run := &Run{
Text: t,
RunProperties: &RunProperties{}, RunProperties: &RunProperties{},
Children: c,
} }
p.Children = append(p.Children, run) p.Children = append(p.Children, run)

View File

@@ -46,10 +46,10 @@ func main() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
r.Drawing.Anchor.Size(r.Drawing.Anchor.Extent.CX/4, r.Drawing.Anchor.Extent.CY/4) r.Children[0].(*docxlib.Drawing).Anchor.Size(r.Children[0].(*docxlib.Drawing).Anchor.Extent.CX/4, r.Children[0].(*docxlib.Drawing).Anchor.Extent.CY/4)
r.Drawing.Anchor.BehindDoc = 1 r.Children[0].(*docxlib.Drawing).Anchor.BehindDoc = 1
r.Drawing.Anchor.PositionH.PosOffset = r.Drawing.Anchor.Extent.CX r.Children[0].(*docxlib.Drawing).Anchor.PositionH.PosOffset = r.Children[0].(*docxlib.Drawing).Anchor.Extent.CX
r.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &docxlib.AAlphaModFix{Amount: 50000} r.Children[0].(*docxlib.Drawing).Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &docxlib.AAlphaModFix{Amount: 50000}
// add text // add text
para1.AddText("test") para1.AddText("test")
para1.AddText("test font size").Size("44") para1.AddText("test font size").Size("44")
@@ -70,13 +70,13 @@ func main() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
r.Drawing.Inline.Size(r.Drawing.Inline.Extent.CX*4/5, r.Drawing.Inline.Extent.CY*4/5) r.Children[0].(*docxlib.Drawing).Inline.Size(r.Children[0].(*docxlib.Drawing).Inline.Extent.CX*4/5, r.Children[0].(*docxlib.Drawing).Inline.Extent.CY*4/5)
para4.AddTab().AddTab() para4.AddTab().AddTab()
r, err = para4.AddInlineDrawingFrom("testdata/fumiama2x.webp") r, err = para4.AddInlineDrawingFrom("testdata/fumiama2x.webp")
if err != nil { if err != nil {
panic(err) panic(err)
} }
r.Drawing.Inline.Size(r.Drawing.Inline.Extent.CX*4/5, r.Drawing.Inline.Extent.CY*4/5) r.Children[0].(*docxlib.Drawing).Inline.Size(r.Children[0].(*docxlib.Drawing).Inline.Extent.CX*4/5, r.Children[0].(*docxlib.Drawing).Inline.Extent.CY*4/5)
para5 := w.AddParagraph().Justification("center") para5 := w.AddParagraph().Justification("center")
// add text // add text

View File

@@ -66,8 +66,6 @@ func (f *Docx) addImageRelation(m Media) string {
// ReferTarget gets the target for a reference // ReferTarget gets the target for a reference
func (f *Docx) ReferTarget(id string) (string, error) { func (f *Docx) ReferTarget(id string) (string, error) {
f.docRelation.mu.RLock()
defer f.docRelation.mu.RUnlock()
for _, a := range f.docRelation.Relationship { for _, a := range f.docRelation.Relationship {
if a.ID == id { if a.ID == id {
return a.Target, nil return a.Target, nil
@@ -78,8 +76,6 @@ func (f *Docx) ReferTarget(id string) (string, error) {
// ReferID gets the rId from target // ReferID gets the rId from target
func (f *Docx) ReferID(target string) (string, error) { func (f *Docx) ReferID(target string) (string, error) {
f.docRelation.mu.RLock()
defer f.docRelation.mu.RUnlock()
for _, a := range f.docRelation.Relationship { for _, a := range f.docRelation.Relationship {
if a.Target == target { if a.Target == target {
return a.ID, nil return a.ID, nil

View File

@@ -24,7 +24,6 @@ import (
"encoding/xml" "encoding/xml"
"io" "io"
"strings" "strings"
"sync"
) )
//nolint:revive,stylecheck //nolint:revive,stylecheck
@@ -48,7 +47,6 @@ func getAtt(atts []xml.Attr, name string) string {
// Body <w:body> // Body <w:body>
type Body struct { type Body struct {
mu sync.Mutex
Items []interface{} Items []interface{}
file *Docx file *Docx
@@ -74,9 +72,7 @@ func (b *Body) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
return err return err
} }
value.file = b.file value.file = b.file
b.mu.Lock()
b.Items = append(b.Items, value) b.Items = append(b.Items, value)
b.mu.Unlock()
case "tbl": case "tbl":
var value WTable var value WTable
err = d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
@@ -84,9 +80,7 @@ func (b *Body) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
return err return err
} }
value.file = b.file value.file = b.file
b.mu.Lock()
b.Items = append(b.Items, value) b.Items = append(b.Items, value)
b.mu.Unlock()
default: default:
err = d.Skip() // skip unsupported tags err = d.Skip() // skip unsupported tags
if err != nil { if err != nil {

View File

@@ -38,12 +38,12 @@ func TestDrawingStructure(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
r.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &AAlphaModFix{Amount: 50000} r.Children[0].(*Drawing).Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &AAlphaModFix{Amount: 50000}
r.Drawing.Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties.CNvPicPr.Locks = &APicLocks{NoChangeAspect: 1} r.Children[0].(*Drawing).Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties.CNvPicPr.Locks = &APicLocks{NoChangeAspect: 1}
r.Drawing.Anchor.Graphic.GraphicData.Pic.SpPr.Xfrm.Rot = 50000 r.Children[0].(*Drawing).Anchor.Graphic.GraphicData.Pic.SpPr.Xfrm.Rot = 50000
para2 := w.AddParagraph().Justification("center") para2 := w.AddParagraph().Justification("center")
para2.AddInlineDrawingFrom("testdata/fumiama.JPG") para2.AddInlineDrawingFrom("testdata/fumiama.JPG")
para2.AddTab().AddTab().AppendTab().AppendTab() para2.AddTab().AddTab().AddTab().AddTab()
para2.AddInlineDrawingFrom("testdata/fumiama2x.webp") para2.AddInlineDrawingFrom("testdata/fumiama2x.webp")
para3 := w.AddParagraph() para3 := w.AddParagraph()

View File

@@ -93,54 +93,58 @@ func (p *Paragraph) String() string {
} }
sb.WriteByte(')') sb.WriteByte(')')
case *Run: case *Run:
switch { for _, c := range o.Children {
case o.Text != nil: switch x := c.(type) {
sb.WriteString(o.Text.Text) case *Text:
case o.Drawing != nil: sb.WriteString(x.Text)
if o.Drawing.Inline != nil && o.Drawing.Inline.Graphic != nil && o.Drawing.Inline.Graphic.GraphicData != nil && o.Drawing.Inline.Graphic.GraphicData.Pic != nil { case *WTab:
sb.WriteString("![inlnim ") sb.WriteByte('\t')
switch { case *Drawing:
case o.Drawing.Inline.DocPr != nil: if x.Inline != nil && x.Inline.Graphic != nil && x.Inline.Graphic.GraphicData != nil && x.Inline.Graphic.GraphicData.Pic != nil {
sb.WriteString(o.Drawing.Inline.DocPr.Name) sb.WriteString("![inlnim ")
case o.Drawing.Inline.Graphic.GraphicData.Pic.NonVisualPicProperties != nil: switch {
sb.WriteString(o.Drawing.Inline.Graphic.GraphicData.Pic.NonVisualPicProperties.NonVisualDrawingProperties.Name) case x.Inline.DocPr != nil:
default: sb.WriteString(x.Inline.DocPr.Name)
sb.WriteString(o.Drawing.Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed) case x.Inline.Graphic.GraphicData.Pic.NonVisualPicProperties != nil:
} sb.WriteString(x.Inline.Graphic.GraphicData.Pic.NonVisualPicProperties.NonVisualDrawingProperties.Name)
sb.WriteString("](") default:
if o.Drawing.Inline.Graphic.GraphicData.Pic.BlipFill != nil { sb.WriteString(x.Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
tgt, err := p.file.ReferTarget(o.Drawing.Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
if err != nil {
sb.WriteString(err.Error())
} else {
h := md5.Sum(p.file.Media(tgt[6:]).Data)
sb.WriteString(hex.EncodeToString(h[:]))
} }
} sb.WriteString("](")
sb.WriteByte(')') if x.Inline.Graphic.GraphicData.Pic.BlipFill != nil {
continue tgt, err := p.file.ReferTarget(x.Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
} if err != nil {
if o.Drawing.Anchor != nil && o.Drawing.Anchor.Graphic != nil && o.Drawing.Anchor.Graphic.GraphicData != nil && o.Drawing.Anchor.Graphic.GraphicData.Pic != nil { sb.WriteString(err.Error())
sb.WriteString("![anchim ") } else {
switch { h := md5.Sum(p.file.Media(tgt[6:]).Data)
case o.Drawing.Anchor.DocPr != nil: sb.WriteString(hex.EncodeToString(h[:]))
sb.WriteString(o.Drawing.Anchor.DocPr.Name) }
case o.Drawing.Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties != nil:
sb.WriteString(o.Drawing.Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties.NonVisualDrawingProperties.Name)
default:
sb.WriteString(o.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
}
sb.WriteString("](")
if o.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill != nil {
tgt, err := p.file.ReferTarget(o.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
if err != nil {
sb.WriteString(err.Error())
} else {
h := md5.Sum(p.file.Media(tgt[6:]).Data)
sb.WriteString(hex.EncodeToString(h[:]))
} }
sb.WriteByte(')')
continue
}
if x.Anchor != nil && x.Anchor.Graphic != nil && x.Anchor.Graphic.GraphicData != nil && x.Anchor.Graphic.GraphicData.Pic != nil {
sb.WriteString("![anchim ")
switch {
case x.Anchor.DocPr != nil:
sb.WriteString(x.Anchor.DocPr.Name)
case x.Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties != nil:
sb.WriteString(x.Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties.NonVisualDrawingProperties.Name)
default:
sb.WriteString(x.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
}
sb.WriteString("](")
if x.Anchor.Graphic.GraphicData.Pic.BlipFill != nil {
tgt, err := p.file.ReferTarget(x.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed)
if err != nil {
sb.WriteString(err.Error())
} else {
h := md5.Sum(p.file.Media(tgt[6:]).Data)
sb.WriteString(hex.EncodeToString(h[:]))
}
}
sb.WriteByte(')')
} }
sb.WriteByte(')')
} }
} }
case *RunProperties: case *RunProperties:

View File

@@ -20,10 +20,6 @@
package docxlib package docxlib
import (
"sync"
)
//nolint:revive,stylecheck //nolint:revive,stylecheck
const ( const (
XMLNS_REL = `http://schemas.openxmlformats.org/package/2006/relationships` XMLNS_REL = `http://schemas.openxmlformats.org/package/2006/relationships`
@@ -35,7 +31,6 @@ const (
// Relationships ... // Relationships ...
type Relationships struct { type Relationships struct {
mu sync.RWMutex
Xmlns string `xml:"xmlns,attr"` Xmlns string `xml:"xmlns,attr"`
Relationship []Relationship Relationship []Relationship
} }

View File

@@ -29,17 +29,13 @@ import (
// Run is part of a paragraph that has its own style. It could be // Run is part of a paragraph that has its own style. It could be
// a piece of text in bold, or a link // a piece of text in bold, or a link
type Run struct { type Run struct {
XMLName xml.Name `xml:"w:r,omitempty"` XMLName xml.Name `xml:"w:r,omitempty"`
RunProperties *RunProperties `xml:"w:rPr,omitempty"` RunProperties *RunProperties `xml:"w:rPr,omitempty"`
FrontTab []struct { //TODO: replace with variable []RunChild
XMLName xml.Name `xml:"w:tab,omitempty"`
}
InstrText string `xml:"w:instrText,omitempty"` InstrText string `xml:"w:instrText,omitempty"`
Text *Text
Drawing *Drawing Children []interface{}
RearTab []struct {
XMLName xml.Name `xml:"w:tab,omitempty"`
}
} }
// UnmarshalXML ... // UnmarshalXML ...
@@ -53,6 +49,8 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
return err return err
} }
var child interface{}
if tt, ok := t.(xml.StartElement); ok { if tt, ok := t.(xml.StartElement); ok {
switch tt.Name.Local { switch tt.Name.Local {
case "rPr": case "rPr":
@@ -62,6 +60,7 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
return err return err
} }
r.RunProperties = &value r.RunProperties = &value
continue
case "instrText": case "instrText":
var value string var value string
err = d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
@@ -69,30 +68,23 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
return err return err
} }
r.InstrText = value r.InstrText = value
continue
case "t": case "t":
var value Text var value Text
err = d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") { if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err return err
} }
r.Text = &value child = &value
case "drawing": case "drawing":
var value Drawing var value Drawing
err = d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") { if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err return err
} }
r.Drawing = &value child = &value
case "tab": case "tab":
if r.InstrText == "" && r.Text == nil && r.Drawing == nil { child = &WTab{}
r.FrontTab = append(r.FrontTab, struct {
XMLName xml.Name "xml:\"w:tab,omitempty\""
}{})
} else {
r.RearTab = append(r.RearTab, struct {
XMLName xml.Name "xml:\"w:tab,omitempty\""
}{})
}
default: default:
err = d.Skip() // skip unsupported tags err = d.Skip() // skip unsupported tags
if err != nil { if err != nil {
@@ -100,6 +92,7 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
} }
continue continue
} }
r.Children = append(r.Children, child)
} }
} }

View File

@@ -25,7 +25,6 @@ import (
"io" "io"
"strconv" "strconv"
"strings" "strings"
"sync"
) )
// WTable represents a table within a Word document. // WTable represents a table within a Word document.
@@ -502,8 +501,6 @@ type WTableRowHeight struct {
// WTableCell represents a cell within a table. // WTableCell represents a cell within a table.
type WTableCell struct { type WTableCell struct {
mu sync.Mutex
XMLName xml.Name `xml:"w:tc,omitempty"` XMLName xml.Name `xml:"w:tc,omitempty"`
TableCellProperties *WTableCellProperties TableCellProperties *WTableCellProperties
Paragraphs []Paragraph `xml:"w:p,omitempty"` Paragraphs []Paragraph `xml:"w:p,omitempty"`
@@ -532,9 +529,7 @@ func (c *WTableCell) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
} }
if len(value.Children) > 0 { if len(value.Children) > 0 {
value.file = c.file value.file = c.file
c.mu.Lock()
c.Paragraphs = append(c.Paragraphs, value) c.Paragraphs = append(c.Paragraphs, value)
c.mu.Unlock()
} }
case "tcPr": case "tcPr":
var value WTableCellProperties var value WTableCellProperties

View File

@@ -41,9 +41,9 @@ func TestTableStructure(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
r.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &AAlphaModFix{Amount: 50000} r.Children[0].(*Drawing).Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &AAlphaModFix{Amount: 50000}
r.Drawing.Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties.CNvPicPr.Locks = &APicLocks{NoChangeAspect: 1} r.Children[0].(*Drawing).Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties.CNvPicPr.Locks = &APicLocks{NoChangeAspect: 1}
r.Drawing.Anchor.Graphic.GraphicData.Pic.SpPr.Xfrm.Rot = 50000 r.Children[0].(*Drawing).Anchor.Graphic.GraphicData.Pic.SpPr.Xfrm.Rot = 50000
para3 := tab1.TableRows[0].TableCells[0].AddParagraph() para3 := tab1.TableRows[0].TableCells[0].AddParagraph()
para3.AddText("first cell") para3.AddText("first cell")