From 8f87a177228eb77c550a84c24552fa15198f28fc 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: Wed, 22 Feb 2023 21:05:15 +0800
Subject: [PATCH] refactor: Paragraph.Children to []interface{}
---
apidrawing.go | 4 +-
apilink.go | 2 +-
apipara.go | 2 +-
apitext.go | 4 +-
cmd/main/main.go | 25 ++-
structdoc_test.go | 510 +---------------------------------------------
structdrawing.go | 46 ++++-
structpara.go | 41 ++--
structrun.go | 2 +-
9 files changed, 81 insertions(+), 555 deletions(-)
diff --git a/apidrawing.go b/apidrawing.go
index 3219b88..34100cb 100644
--- a/apidrawing.go
+++ b/apidrawing.go
@@ -83,7 +83,7 @@ func (p *Paragraph) AddInlineDrawing(pic []byte) (*Run, error) {
Drawing: d,
RunProperties: &RunProperties{},
}
- p.Children = append(p.Children, ParagraphChild{Run: run})
+ p.Children = append(p.Children, run)
return run, nil
}
@@ -191,7 +191,7 @@ func (p *Paragraph) AddAnchorDrawing(pic []byte) (*Run, error) {
Drawing: d,
RunProperties: &RunProperties{},
}
- p.Children = append(p.Children, ParagraphChild{Run: run})
+ p.Children = append(p.Children, run)
return run, nil
}
diff --git a/apilink.go b/apilink.go
index 8178a33..fb6727c 100644
--- a/apilink.go
+++ b/apilink.go
@@ -19,7 +19,7 @@ func (p *Paragraph) AddLink(text string, link string) *Hyperlink {
},
}
- p.Children = append(p.Children, ParagraphChild{Link: hyperlink})
+ p.Children = append(p.Children, hyperlink)
return hyperlink
}
diff --git a/apipara.go b/apipara.go
index 4151631..e7b9407 100644
--- a/apipara.go
+++ b/apipara.go
@@ -3,7 +3,7 @@ package docxlib
// AddParagraph adds a new paragraph
func (f *Docx) AddParagraph() *Paragraph {
p := &Paragraph{
- Children: make([]ParagraphChild, 0, 64),
+ Children: make([]interface{}, 0, 64),
file: f,
}
diff --git a/apitext.go b/apitext.go
index 3442f6d..d982862 100644
--- a/apitext.go
+++ b/apitext.go
@@ -10,7 +10,7 @@ func (p *Paragraph) AddTab() *Run {
XMLName xml.Name "xml:\"w:tab,omitempty\""
}{{}},
}
- p.Children = append(p.Children, ParagraphChild{Run: run})
+ p.Children = append(p.Children, run)
return run
}
@@ -29,7 +29,7 @@ func (p *Paragraph) AddText(text string) *Run {
RunProperties: &RunProperties{},
}
- p.Children = append(p.Children, ParagraphChild{Run: run})
+ p.Children = append(p.Children, run)
return run
}
diff --git a/cmd/main/main.go b/cmd/main/main.go
index 528e043..bf3f45e 100644
--- a/cmd/main/main.go
+++ b/cmd/main/main.go
@@ -96,29 +96,28 @@ func main() {
for _, para := range doc.Document.Body.Paragraphs {
fmt.Println("New paragraph")
for _, child := range para.Children {
- if child.Run != nil {
- if child.Run.Text != nil {
- fmt.Printf("\tWe've found a new run with the text ->%s\n", child.Run.Text.Text)
+ switch o := child.(type) {
+ case *docxlib.Run:
+ if o.Text != nil {
+ fmt.Printf("\tWe've found a new run with the text ->%s\n", o.Text.Text)
}
- if child.Run.Drawing != nil {
- if child.Run.Drawing.Inline != nil {
- fmt.Printf("\tWe've found a new run with the inline drawing ->%s\n", child.Run.Drawing.Inline.DocPr.Name)
+ if o.Drawing != nil {
+ if o.Drawing.Inline != nil {
+ fmt.Printf("\tWe've found a new run with the inline drawing ->%s\n", o.Drawing.Inline.DocPr.Name)
}
- if child.Run.Drawing.Anchor != nil {
- fmt.Printf("\tWe've found a new run with the anchor drawing ->%s\n", child.Run.Drawing.Anchor.DocPr.Name)
+ if o.Drawing.Anchor != nil {
+ fmt.Printf("\tWe've found a new run with the anchor drawing ->%s\n", o.Drawing.Anchor.DocPr.Name)
}
}
- }
- if child.Link != nil {
- id := child.Link.ID
- text := child.Link.Run.InstrText
+ case *docxlib.Hyperlink:
+ id := o.ID
+ text := o.Run.InstrText
link, err := doc.ReferTarget(id)
if err != nil {
fmt.Printf("\tWe found a link with id %s and text %s without target\n", id, text)
} else {
fmt.Printf("\tWe've found a new hyperlink with ref %s and the text %s\n", link, text)
}
-
}
}
fmt.Print("End of paragraph\n\n")
diff --git a/structdoc_test.go b/structdoc_test.go
index 3e76fa4..91e917b 100644
--- a/structdoc_test.go
+++ b/structdoc_test.go
@@ -37,10 +37,10 @@ func TestUnmarshalPlainStructure(t *testing.T) {
t.Fatalf("We were not able to parse paragraph %d", i)
}
for _, child := range p.Children {
- if child.Link == nil && child.Properties == nil && child.Run == nil {
+ if child == nil {
t.Fatalf("There are Paragraph children with all fields nil")
}
- if child.Link != nil && child.Link.ID == "" {
+ if o, ok := child.(*Hyperlink); ok && o.ID == "" {
t.Fatalf("We have a link without ID")
}
}
@@ -48,510 +48,6 @@ func TestUnmarshalPlainStructure(t *testing.T) {
}
}
-const drawing_doc = `
-
-
-
-
-
-
-
-
-
-
-
-
- 直接粘贴
-
-
-
-
-
-
-
-
- inline
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一行2个
-
-
- inline
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一行2个组合
-
-
- inline
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一个 浮于上方
-
-
-
-
-
- 右侧对齐
-
-
-
-
-
- 左
-
-
- 11.32cm
-
-
-
-
-
- 顶
-
-
- 23.73cm
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 2935605
-
-
- 97790
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-`
-
-func TestUnmarshalDrawingStructure(t *testing.T) {
- doc := Document{
- XMLW: XMLNS_W,
- XMLR: XMLNS_R,
- XMLWP: XMLNS_WP,
- // XMLWP14: XMLNS_WP14,
- XMLName: xml.Name{Space: XMLNS_W, Local: "document"}}
- err := xml.Unmarshal(StringToBytes(drawing_doc), &doc)
- if err != nil {
- t.Fatal(err)
- }
- if len(doc.Body.Paragraphs) != 8 {
- t.Fatalf("We expected %d paragraphs, we got %d", 8, len(doc.Body.Paragraphs))
- }
- for i, p := range doc.Body.Paragraphs {
- if len(p.Children) == 0 {
- t.Fatalf("We were not able to parse paragraph %d", i)
- }
- for j, child := range p.Children {
- if child.Link == nil && child.Properties == nil && child.Run == nil {
- t.Fatalf("There are Paragraph children with all fields nil")
- }
- if child.Run != nil && child.Run.Text == nil && child.Run.InstrText == "" && child.Run.Drawing == nil {
- t.Fatalf("We have a run with no text and drawing")
- }
- if child.Link != nil && child.Link.ID == "" {
- t.Fatalf("We have a link without ID")
- }
- if child.Run != nil && child.Run.Drawing != nil {
- t.Log("fild drawing at aragraph", i, ", child", j)
- if child.Run.Drawing.Inline != nil {
- if child.Run.Drawing.Inline.DistT != 0 || child.Run.Drawing.Inline.DistB != 1 || child.Run.Drawing.Inline.DistL != 2 || child.Run.Drawing.Inline.DistR != 3 {
- t.Fatal("unexpected inline dist")
- }
- }
- }
- }
- }
-}
-
func TestInlineDrawingStructure(t *testing.T) {
w := NewA4()
// add new paragraph
@@ -563,6 +59,8 @@ func TestInlineDrawingStructure(t *testing.T) {
t.Fatal(err)
}
r.Drawing.Anchor.Graphic.GraphicData.Pic.BlipFill.Blip.AlphaModFix = &AAlphaModFix{Amount: 50000}
+ r.Drawing.Anchor.Graphic.GraphicData.Pic.NonVisualPicProperties.CNvPicPr.Locks = &APicLocks{NoChangeAspect: 1}
+ r.Drawing.Anchor.Graphic.GraphicData.Pic.SpPr.Xfrm.Rot = 50000
para2 := w.AddParagraph().Justification("center")
para2.AddInlineDrawingFrom("testdata/fumiama.JPG")
para2.AddTab().AddTab().AppendTab().AppendTab()
diff --git a/structdrawing.go b/structdrawing.go
index 7402bb1..69a8fe8 100644
--- a/structdrawing.go
+++ b/structdrawing.go
@@ -429,7 +429,7 @@ func (p *PICPic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type PICNonVisualPicProperties struct {
XMLName xml.Name `xml:"pic:nvPicPr,omitempty"`
NonVisualDrawingProperties PICNonVisualDrawingProperties
- CNvPicPr struct{} `xml:"pic:cNvPicPr"`
+ CNvPicPr PicCNvPicPr
}
func (p *PICNonVisualPicProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
@@ -448,6 +448,8 @@ func (p *PICNonVisualPicProperties) UnmarshalXML(d *xml.Decoder, start xml.Start
case "cNvPr":
p.NonVisualDrawingProperties.ID = getAtt(tt.Attr, "id")
p.NonVisualDrawingProperties.Name = getAtt(tt.Attr, "name")
+ case "cNvPicPr":
+ d.DecodeElement(&p.CNvPicPr, &tt)
default:
continue
}
@@ -457,6 +459,48 @@ func (p *PICNonVisualPicProperties) UnmarshalXML(d *xml.Decoder, start xml.Start
return nil
}
+// PicCNvPicPr represents the non-visual properties of a picture.
+type PicCNvPicPr struct {
+ XMLName xml.Name `xml:"pic:cNvPicPr,omitempty"`
+ Locks *APicLocks
+}
+
+func (p *PicCNvPicPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
+ // Loop through XML tokens
+ for {
+ t, err := d.Token()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+
+ // Switch based on token type
+ switch tt := t.(type) {
+ case xml.StartElement:
+ switch tt.Name.Local {
+ case "picLocks":
+ var value APicLocks
+ value.NoChangeAspect, err = strconv.Atoi(getAtt(tt.Attr, "noChangeAspect"))
+ if err != nil {
+ return err
+ }
+ p.Locks = &value
+ default:
+ continue
+ }
+ }
+ }
+ return nil
+}
+
+// APicLocks represents the locks applied to a picture.
+type APicLocks struct {
+ XMLName xml.Name `xml:"a:picLocks,omitempty"`
+ NoChangeAspect int `xml:"noChangeAspect,attr"`
+}
+
// PICNonVisualDrawingProperties represents the non-visual drawing properties of a picture in a Word document.
type PICNonVisualDrawingProperties struct {
XMLName xml.Name `xml:"pic:cNvPr,omitempty"`
diff --git a/structpara.go b/structpara.go
index 2806518..effe6b4 100644
--- a/structpara.go
+++ b/structpara.go
@@ -35,16 +35,10 @@ func (p *ParagraphProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
}
-type ParagraphChild struct {
- Link *Hyperlink `xml:"w:hyperlink,omitempty"`
- Run *Run `xml:"w:r,omitempty"`
- Properties *RunProperties `xml:"w:rPr,omitempty"`
-}
-
type Paragraph struct {
XMLName xml.Name `xml:"w:p,omitempty"`
Properties *ParagraphProperties
- Children []ParagraphChild // Children will generate an unnecessary tag ... and we skip it by a self-defined xml.Marshaler
+ Children []interface{} // Children will generate an unnecessary tag ... and we skip it by a self-defined xml.Marshaler
file *Docx
}
@@ -52,10 +46,10 @@ type Paragraph struct {
func (p *Paragraph) String() string {
sb := strings.Builder{}
for _, c := range p.Children {
- switch {
- case c.Link != nil:
- id := c.Link.ID
- text := c.Link.Run.InstrText
+ switch o := c.(type) {
+ case *Hyperlink:
+ id := o.ID
+ text := o.Run.InstrText
link, err := p.file.ReferTarget(id)
sb.WriteString(text)
sb.WriteByte('(')
@@ -65,9 +59,9 @@ func (p *Paragraph) String() string {
sb.WriteString(link)
}
sb.WriteByte(')')
- case c.Run != nil:
+ case *Run:
sb.WriteString("run") //TODO: implement
- case c.Properties != nil:
+ case *RunProperties:
sb.WriteString("prop") //TODO: implement
default:
continue
@@ -88,16 +82,7 @@ func (p *Paragraph) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
}
}
for _, c := range p.Children {
- switch {
- case c.Link != nil:
- err = e.Encode(c.Link)
- case c.Run != nil:
- err = e.Encode(c.Run)
- case c.Properties != nil:
- err = e.Encode(c.Properties)
- default:
- continue
- }
+ e.Encode(c)
if err != nil {
return err
}
@@ -106,7 +91,7 @@ func (p *Paragraph) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
}
func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
- children := make([]ParagraphChild, 0, 64)
+ children := make([]interface{}, 0, 64)
for {
t, err := d.Token()
if err == io.EOF {
@@ -117,7 +102,7 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
}
switch tt := t.(type) {
case xml.StartElement:
- var elem ParagraphChild
+ var elem interface{}
switch tt.Name.Local {
case "hyperlink":
var value Hyperlink
@@ -130,15 +115,15 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if anchor != "" {
value.ID = anchor
}
- elem.Link = &value
+ elem = &value
case "r":
var value Run
d.DecodeElement(&value, &tt)
- elem.Run = &value
+ elem = &value
case "rPr":
var value RunProperties
d.DecodeElement(&value, &tt)
- elem.Properties = &value
+ elem = &value
case "pPr":
var value ParagraphProperties
d.DecodeElement(&value, &tt)
diff --git a/structrun.go b/structrun.go
index 396bf67..aab8573 100644
--- a/structrun.go
+++ b/structrun.go
@@ -10,7 +10,7 @@ import (
type Run struct {
XMLName xml.Name `xml:"w:r,omitempty"`
RunProperties *RunProperties `xml:"w:rPr,omitempty"`
- FrontTab []struct {
+ FrontTab []struct { // TODO: replace with variable []RunChild
XMLName xml.Name `xml:"w:tab,omitempty"`
}
InstrText string `xml:"w:instrText,omitempty"`