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

make lint happy

This commit is contained in:
源文雨
2023-02-23 14:34:44 +08:00
parent 59cce024f7
commit fa053fefd4
13 changed files with 350 additions and 170 deletions

View File

@@ -2,14 +2,14 @@ package docxlib
// AddParagraph adds a new paragraph // AddParagraph adds a new paragraph
func (f *Docx) AddParagraph() *Paragraph { func (f *Docx) AddParagraph() *Paragraph {
p := &Paragraph{ f.Document.Body.mu.Lock()
defer f.Document.Body.mu.Unlock()
f.Document.Body.Paragraphs = append(f.Document.Body.Paragraphs, Paragraph{
Children: make([]interface{}, 0, 64), Children: make([]interface{}, 0, 64),
file: f, file: f,
} })
f.Document.Body.Paragraphs = append(f.Document.Body.Paragraphs, p) return &f.Document.Body.Paragraphs[len(f.Document.Body.Paragraphs)-1]
return p
} }
// Justification allows to set para's horizonal alignment // Justification allows to set para's horizonal alignment

View File

@@ -15,16 +15,13 @@ func newEmptyA4File() *Docx {
XMLR: XMLNS_R, XMLR: XMLNS_R,
XMLWP: XMLNS_WP, XMLWP: XMLNS_WP,
// XMLWP14: XMLNS_WP14, // XMLWP14: XMLNS_WP14,
Body: &Body{ Body: Body{
XMLName: xml.Name{ Paragraphs: make([]Paragraph, 0, 64),
Space: "w",
},
Paragraphs: make([]*Paragraph, 0, 64),
}, },
}, },
DocRelation: Relationships{ DocRelation: Relationships{
Xmlns: XMLNS_REL, Xmlns: XMLNS_REL,
Relationships: []*Relationship{ Relationship: []Relationship{
{ {
ID: "rId1", ID: "rId1",
Type: `http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles`, Type: `http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles`,
@@ -69,6 +66,6 @@ func newEmptyA4File() *Docx {
}, },
buf: bytes.NewBuffer(make([]byte, 0, 1024*1024*4)), buf: bytes.NewBuffer(make([]byte, 0, 1024*1024*4)),
} }
docx.Document.file = docx docx.Document.Body.file = docx
return docx return docx
} }

12
link.go
View File

@@ -17,14 +17,14 @@ var (
// //
// this func is not thread-safe // this func is not thread-safe
func (f *Docx) addLinkRelation(link string) string { func (f *Docx) addLinkRelation(link string) string {
rel := &Relationship{ rel := Relationship{
ID: "rId" + strconv.Itoa(int(atomic.AddUintptr(&f.rId, 1))), ID: "rId" + strconv.Itoa(int(atomic.AddUintptr(&f.rId, 1))),
Type: REL_HYPERLINK, Type: REL_HYPERLINK,
Target: link, Target: link,
TargetMode: REL_TARGETMODE, TargetMode: REL_TARGETMODE,
} }
f.DocRelation.Relationships = append(f.DocRelation.Relationships, rel) f.DocRelation.Relationship = append(f.DocRelation.Relationship, rel)
return rel.ID return rel.ID
} }
@@ -33,13 +33,13 @@ func (f *Docx) addLinkRelation(link string) string {
// //
// this func is not thread-safe // this func is not thread-safe
func (f *Docx) addImageRelation(m Media) string { func (f *Docx) addImageRelation(m Media) string {
rel := &Relationship{ rel := Relationship{
ID: "rId" + strconv.Itoa(int(atomic.AddUintptr(&f.rId, 1))), ID: "rId" + strconv.Itoa(int(atomic.AddUintptr(&f.rId, 1))),
Type: REL_IMAGE, Type: REL_IMAGE,
Target: "media/" + m.Name, Target: "media/" + m.Name,
} }
f.DocRelation.Relationships = append(f.DocRelation.Relationships, rel) f.DocRelation.Relationship = append(f.DocRelation.Relationship, rel)
return rel.ID return rel.ID
} }
@@ -48,7 +48,7 @@ func (f *Docx) addImageRelation(m Media) string {
func (f *Docx) ReferTarget(id string) (string, error) { func (f *Docx) ReferTarget(id string) (string, error) {
f.DocRelation.mu.RLock() f.DocRelation.mu.RLock()
defer f.DocRelation.mu.RUnlock() defer f.DocRelation.mu.RUnlock()
for _, a := range f.DocRelation.Relationships { for _, a := range f.DocRelation.Relationship {
if a.ID == id { if a.ID == id {
return a.Target, nil return a.Target, nil
} }
@@ -60,7 +60,7 @@ func (f *Docx) ReferTarget(id string) (string, error) {
func (f *Docx) ReferID(target string) (string, error) { func (f *Docx) ReferID(target string) (string, error) {
f.DocRelation.mu.RLock() f.DocRelation.mu.RLock()
defer f.DocRelation.mu.RUnlock() defer f.DocRelation.mu.RUnlock()
for _, a := range f.DocRelation.Relationships { for _, a := range f.DocRelation.Relationship {
if a.Target == target { if a.Target == target {
return a.ID, nil return a.ID, nil
} }

View File

@@ -31,7 +31,7 @@ func (f *Docx) pack(zipWriter *zip.Writer) (err error) {
} }
files["word/_rels/document.xml.rels"] = marshaller{data: &f.DocRelation} files["word/_rels/document.xml.rels"] = marshaller{data: &f.DocRelation}
files["word/document.xml"] = marshaller{data: f.Document} files["word/document.xml"] = marshaller{data: &f.Document}
for _, m := range f.media { for _, m := range f.media {
files[m.String()] = bytes.NewReader(m.Data) files[m.String()] = bytes.NewReader(m.Data)

View File

@@ -3,6 +3,8 @@ package docxlib
import ( import (
"encoding/xml" "encoding/xml"
"io" "io"
"strings"
"sync"
) )
const ( const (
@@ -24,27 +26,13 @@ func getAtt(atts []xml.Attr, name string) string {
} }
type Body struct { type Body struct {
XMLName xml.Name `xml:"w:body"` mu sync.Mutex
Paragraphs []*Paragraph `xml:"w:p,omitempty"` Paragraphs []Paragraph `xml:"w:p,omitempty"`
}
type Document struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main document"`
XMLW string `xml:"xmlns:w,attr"` // cannot be unmarshalled in
XMLR string `xml:"xmlns:r,attr,omitempty"` // cannot be unmarshalled in
XMLWP string `xml:"xmlns:wp,attr,omitempty"` // cannot be unmarshalled in
XMLWP14 string `xml:"xmlns:wp14,attr,omitempty"` // cannot be unmarshalled in
Body *Body
file *Docx file *Docx
} }
func (doc *Document) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (b *Body) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if doc.Body == nil {
doc.Body = &Body{
Paragraphs: make([]*Paragraph, 0, 64),
}
}
for { for {
t, err := d.Token() t, err := d.Token()
if err == io.EOF { if err == io.EOF {
@@ -56,19 +44,59 @@ func (doc *Document) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
switch tt := t.(type) { switch tt := t.(type) {
case xml.StartElement: case xml.StartElement:
switch tt.Name.Local { if tt.Name.Local == "p" {
case "body":
case "p":
var value Paragraph var value Paragraph
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if len(value.Children) > 0 { if err != nil && !strings.HasPrefix(err.Error(), "expected") {
value.file = doc.file return err
doc.Body.Paragraphs = append(doc.Body.Paragraphs, &value) }
if len(value.Children) > 0 {
value.file = b.file
b.mu.Lock()
b.Paragraphs = append(b.Paragraphs, value)
b.mu.Unlock()
} }
default:
d.Skip()
continue continue
} }
err = d.Skip() // skip unsupported tags
if err != nil {
return err
}
}
}
return nil
}
type Document struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main document"`
XMLW string `xml:"xmlns:w,attr"` // cannot be unmarshalled in
XMLR string `xml:"xmlns:r,attr,omitempty"` // cannot be unmarshalled in
XMLWP string `xml:"xmlns:wp,attr,omitempty"` // cannot be unmarshalled in
// XMLWP14 string `xml:"xmlns:wp14,attr,omitempty"` // cannot be unmarshalled in
Body Body `xml:"w:body"`
}
func (doc *Document) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for {
t, err := d.Token()
if err == io.EOF {
break
}
if err != nil {
return err
}
switch tt := t.(type) {
case xml.StartElement:
if tt.Name.Local == "body" {
err = d.DecodeElement(&doc.Body, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
}
} }
} }

View File

@@ -2,9 +2,6 @@ package docxlib
import ( import (
"encoding/xml" "encoding/xml"
"hash/crc64"
"io"
"os"
"testing" "testing"
) )
@@ -47,76 +44,3 @@ func TestUnmarshalPlainStructure(t *testing.T) {
} }
} }
} }
func TestInlineDrawingStructure(t *testing.T) {
w := NewA4()
// add new paragraph
para1 := w.AddParagraph()
// add text
para1.AddText("直接粘贴 inline").AddTab()
r, err := para1.AddAnchorDrawingFrom("testdata/fumiama.JPG")
if err != nil {
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()
para2.AddInlineDrawingFrom("testdata/fumiama2x.webp")
para3 := w.AddParagraph()
para3.AddInlineDrawingFrom("testdata/fumiamayoko.png")
f, err := os.Create("TestMarshalInlineDrawingStructure.xml")
if err != nil {
t.Fatal(err)
}
defer f.Close()
_, err = marshaller{data: w.Document}.WriteTo(f)
if err != nil {
t.Fatal(err)
}
_, err = f.Seek(0, io.SeekStart)
if err != nil {
t.Fatal(err)
}
w = NewA4()
err = xml.NewDecoder(f).Decode(&w.Document)
if err != nil {
t.Fatal(err)
}
f1, err := os.Create("TestUnmarshalInlineDrawingStructure.xml")
if err != nil {
t.Fatal(err)
}
defer f1.Close()
_, err = marshaller{data: w.Document}.WriteTo(f1)
if err != nil {
t.Fatal(err)
}
_, err = f.Seek(0, io.SeekStart)
if err != nil {
t.Fatal(err)
}
_, err = f1.Seek(0, io.SeekStart)
if err != nil {
t.Fatal(err)
}
h := crc64.New(crc64.MakeTable(crc64.ECMA))
_, err = io.Copy(h, f)
if err != nil {
t.Fatal(err)
}
md51 := h.Sum64()
h.Reset()
_, err = io.Copy(h, f1)
if err != nil {
t.Fatal(err)
}
md52 := h.Sum64()
if md51 != md52 {
t.Fail()
}
}

View File

@@ -4,6 +4,7 @@ import (
"encoding/xml" "encoding/xml"
"io" "io"
"strconv" "strconv"
"strings"
) )
const ( const (
@@ -38,10 +39,16 @@ func (r *Drawing) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "inline": case "inline":
r.Inline = new(WPInline) r.Inline = new(WPInline)
d.DecodeElement(r.Inline, &tt) err = d.DecodeElement(r.Inline, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "anchor": case "anchor":
r.Anchor = new(WPAnchor) r.Anchor = new(WPAnchor)
d.DecodeElement(r.Anchor, &tt) err = d.DecodeElement(r.Anchor, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
default: default:
continue continue
} }
@@ -138,14 +145,23 @@ func (r *WPInline) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err err
} }
case "docPr": case "docPr":
r.DocPr = new(WPDocPr) r.DocPr = new(WPDocPr)
d.DecodeElement(r.DocPr, &tt) err = d.DecodeElement(r.DocPr, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "cNvGraphicFramePr": case "cNvGraphicFramePr":
var value WPCNvGraphicFramePr var value WPCNvGraphicFramePr
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.CNvGraphicFramePr = &value r.CNvGraphicFramePr = &value
case "graphic": case "graphic":
var value AGraphic var value AGraphic
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.Graphic = &value r.Graphic = &value
default: default:
continue continue
@@ -285,7 +301,10 @@ func (w *WPCNvGraphicFramePr) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
switch tt.Name.Local { switch tt.Name.Local {
case "graphicFrameLocks": case "graphicFrameLocks":
var value AGraphicFrameLocks var value AGraphicFrameLocks
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
value.NoChangeAspect, err = strconv.Atoi(getAtt(tt.Attr, "noChangeAspect")) value.NoChangeAspect, err = strconv.Atoi(getAtt(tt.Attr, "noChangeAspect"))
if err != nil { if err != nil {
return err return err
@@ -336,7 +355,10 @@ func (a *AGraphic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "graphicData": case "graphicData":
var value AGraphicData var value AGraphicData
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
value.URI = getAtt(tt.Attr, "uri") value.URI = getAtt(tt.Attr, "uri")
a.GraphicData = &value a.GraphicData = &value
default: default:
@@ -370,7 +392,10 @@ func (a *AGraphicData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) erro
switch tt.Name.Local { switch tt.Name.Local {
case "pic": case "pic":
var value PICPic var value PICPic
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
value.XMLPIC = getAtt(tt.Attr, "pic") value.XMLPIC = getAtt(tt.Attr, "pic")
a.Pic = &value a.Pic = &value
default: default:
@@ -406,15 +431,24 @@ func (p *PICPic) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "nvPicPr": case "nvPicPr":
var value PICNonVisualPicProperties var value PICNonVisualPicProperties
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
p.NonVisualPicProperties = &value p.NonVisualPicProperties = &value
case "blipFill": case "blipFill":
var value PICBlipFill var value PICBlipFill
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
p.BlipFill = &value p.BlipFill = &value
case "spPr": case "spPr":
var value PICSpPr var value PICSpPr
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
p.SpPr = &value p.SpPr = &value
default: default:
continue continue
@@ -449,7 +483,10 @@ func (p *PICNonVisualPicProperties) UnmarshalXML(d *xml.Decoder, start xml.Start
p.NonVisualDrawingProperties.ID = getAtt(tt.Attr, "id") p.NonVisualDrawingProperties.ID = getAtt(tt.Attr, "id")
p.NonVisualDrawingProperties.Name = getAtt(tt.Attr, "name") p.NonVisualDrawingProperties.Name = getAtt(tt.Attr, "name")
case "cNvPicPr": case "cNvPicPr":
d.DecodeElement(&p.CNvPicPr, &tt) err = d.DecodeElement(&p.CNvPicPr, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
default: default:
continue continue
} }
@@ -529,9 +566,15 @@ func (p *PICBlipFill) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
case xml.StartElement: case xml.StartElement:
switch tt.Name.Local { switch tt.Name.Local {
case "blip": case "blip":
d.DecodeElement(&p.Blip, &tt) err = d.DecodeElement(&p.Blip, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "stretch": case "stretch":
d.DecodeElement(&p.Stretch, &tt) err = d.DecodeElement(&p.Stretch, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
default: default:
continue continue
} }
@@ -626,9 +669,15 @@ func (p *PICSpPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
case xml.StartElement: case xml.StartElement:
switch tt.Name.Local { switch tt.Name.Local {
case "xfrm": case "xfrm":
d.DecodeElement(&p.Xfrm, &tt) err = d.DecodeElement(&p.Xfrm, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "prstGeom": case "prstGeom":
d.DecodeElement(&p.PrstGeom, &tt) err = d.DecodeElement(&p.PrstGeom, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
p.PrstGeom.Prst = getAtt(tt.Attr, "prst") p.PrstGeom.Prst = getAtt(tt.Attr, "prst")
default: default:
continue continue
@@ -881,17 +930,29 @@ func (r *WPAnchor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err err
case "positionH": case "positionH":
r.PositionH = new(WPPositionH) r.PositionH = new(WPPositionH)
// r.PositionH.RelativeFrom = getAtt(tt.Attr, "relativeFrom") // r.PositionH.RelativeFrom = getAtt(tt.Attr, "relativeFrom")
d.DecodeElement(&r.PositionH, &tt) err = d.DecodeElement(&r.PositionH, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "positionV": case "positionV":
r.PositionV = new(WPPositionV) r.PositionV = new(WPPositionV)
// r.PositionV.RelativeFrom = getAtt(tt.Attr, "relativeFrom") // r.PositionV.RelativeFrom = getAtt(tt.Attr, "relativeFrom")
d.DecodeElement(&r.PositionV, &tt) err = d.DecodeElement(&r.PositionV, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "extent": case "extent":
r.Extent = new(WPExtent) r.Extent = new(WPExtent)
d.DecodeElement(&r.Extent, &tt) err = d.DecodeElement(&r.Extent, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "effectExtent": case "effectExtent":
r.EffectExtent = new(WPEffectExtent) r.EffectExtent = new(WPEffectExtent)
d.DecodeElement(&r.EffectExtent, &tt) err = d.DecodeElement(&r.EffectExtent, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "wrapNone": case "wrapNone":
r.WrapNone = &struct{}{} r.WrapNone = &struct{}{}
case "wrapSquare": case "wrapSquare":
@@ -899,13 +960,22 @@ func (r *WPAnchor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err err
r.WrapSquare.WrapText = getAtt(tt.Attr, "wrapText") r.WrapSquare.WrapText = getAtt(tt.Attr, "wrapText")
case "docPr": case "docPr":
r.DocPr = new(WPDocPr) r.DocPr = new(WPDocPr)
d.DecodeElement(r.DocPr, &tt) err = d.DecodeElement(r.DocPr, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "cNvGraphicFramePr": case "cNvGraphicFramePr":
r.CNvGraphicFramePr = new(WPCNvGraphicFramePr) r.CNvGraphicFramePr = new(WPCNvGraphicFramePr)
d.DecodeElement(r.CNvGraphicFramePr, &tt) err = d.DecodeElement(r.CNvGraphicFramePr, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
case "graphic": case "graphic":
r.Graphic = new(AGraphic) r.Graphic = new(AGraphic)
d.DecodeElement(&r.Graphic, &tt) err = d.DecodeElement(&r.Graphic, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
default: default:
continue continue
} }
@@ -949,7 +1019,7 @@ func (r *WPPositionH) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
switch tt.Name.Local { switch tt.Name.Local {
case "posOffset": case "posOffset":
err = d.DecodeElement(&r.PosOffset, &tt) err = d.DecodeElement(&r.PosOffset, &tt)
if err != nil { if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err return err
} }
default: default:
@@ -988,7 +1058,7 @@ func (r *WPPositionV) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
switch tt.Name.Local { switch tt.Name.Local {
case "posOffset": case "posOffset":
err = d.DecodeElement(&r.PosOffset, &tt) err = d.DecodeElement(&r.PosOffset, &tt)
if err != nil { if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err return err
} }
default: default:

82
structdrawing_test.go Normal file
View File

@@ -0,0 +1,82 @@
package docxlib
import (
"encoding/xml"
"hash/crc64"
"io"
"os"
"testing"
)
func TestDrawingStructure(t *testing.T) {
w := NewA4()
// add new paragraph
para1 := w.AddParagraph()
// add text
para1.AddText("直接粘贴 inline").AddTab()
r, err := para1.AddAnchorDrawingFrom("testdata/fumiama.JPG")
if err != nil {
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()
para2.AddInlineDrawingFrom("testdata/fumiama2x.webp")
para3 := w.AddParagraph()
para3.AddInlineDrawingFrom("testdata/fumiamayoko.png")
f, err := os.Create("TestMarshalInlineDrawingStructure.xml")
if err != nil {
t.Fatal(err)
}
defer f.Close()
_, err = marshaller{data: &w.Document}.WriteTo(f)
if err != nil {
t.Fatal(err)
}
_, err = f.Seek(0, io.SeekStart)
if err != nil {
t.Fatal(err)
}
w = NewA4()
err = xml.NewDecoder(f).Decode(&w.Document)
if err != nil {
t.Fatal(err)
}
f1, err := os.Create("TestUnmarshalInlineDrawingStructure.xml")
if err != nil {
t.Fatal(err)
}
defer f1.Close()
_, err = marshaller{data: &w.Document}.WriteTo(f1)
if err != nil {
t.Fatal(err)
}
_, err = f.Seek(0, io.SeekStart)
if err != nil {
t.Fatal(err)
}
_, err = f1.Seek(0, io.SeekStart)
if err != nil {
t.Fatal(err)
}
h := crc64.New(crc64.MakeTable(crc64.ECMA))
_, err = io.Copy(h, f)
if err != nil {
t.Fatal(err)
}
crc1 := h.Sum64()
h.Reset()
_, err = io.Copy(h, f1)
if err != nil {
t.Fatal(err)
}
crc2 := h.Sum64()
if crc1 != crc2 {
t.Fail()
}
}

View File

@@ -3,6 +3,7 @@ package docxlib
import ( import (
"encoding/xml" "encoding/xml"
"io" "io"
"strings"
) )
// Hyperlink element contains links // Hyperlink element contains links
@@ -25,9 +26,10 @@ func (r *Hyperlink) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt := t.(type) { switch tt := t.(type) {
case xml.StartElement: case xml.StartElement:
if tt.Name.Local == "r" { if tt.Name.Local == "r" {
d.DecodeElement(&r.Run, &tt) err = d.DecodeElement(&r.Run, &tt)
} else { if err != nil && !strings.HasPrefix(err.Error(), "expected") {
continue return err
}
} }
} }

View File

@@ -36,7 +36,7 @@ func (p *ParagraphProperties) UnmarshalXML(d *xml.Decoder, start xml.StartElemen
} }
type Paragraph struct { type Paragraph struct {
XMLName xml.Name `xml:"w:p,omitempty"` // XMLName xml.Name `xml:"w:p,omitempty"`
Properties *ParagraphProperties Properties *ParagraphProperties
Children []interface{} // Children will generate an unnecessary tag <Children> ... </Children> and we skip it by a self-defined xml.Marshaler Children []interface{} // Children will generate an unnecessary tag <Children> ... </Children> and we skip it by a self-defined xml.Marshaler
@@ -106,7 +106,10 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "hyperlink": case "hyperlink":
var value Hyperlink var value Hyperlink
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
id := getAtt(tt.Attr, "id") id := getAtt(tt.Attr, "id")
anchor := getAtt(tt.Attr, "anchor") anchor := getAtt(tt.Attr, "anchor")
if id != "" { if id != "" {
@@ -118,15 +121,24 @@ func (p *Paragraph) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
elem = &value elem = &value
case "r": case "r":
var value Run var value Run
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
elem = &value elem = &value
case "rPr": case "rPr":
var value RunProperties var value RunProperties
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
elem = &value elem = &value
case "pPr": case "pPr":
var value ParagraphProperties var value ParagraphProperties
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
p.Properties = &value p.Properties = &value
continue continue
default: default:

View File

@@ -1,7 +1,6 @@
package docxlib package docxlib
import ( import (
"encoding/xml"
"sync" "sync"
) )
@@ -14,16 +13,14 @@ const (
) )
type Relationships struct { type Relationships struct {
mu sync.RWMutex mu sync.RWMutex
XMLName xml.Name `xml:"Relationships"` Xmlns string `xml:"xmlns,attr"`
Xmlns string `xml:"xmlns,attr"` Relationship []Relationship
Relationships []*Relationship `xml:"Relationship"`
} }
type Relationship struct { type Relationship struct {
XMLName xml.Name `xml:"Relationship"` ID string `xml:"Id,attr"`
ID string `xml:"Id,attr"` Type string `xml:"Type,attr"`
Type string `xml:"Type,attr"` Target string `xml:"Target,attr"`
Target string `xml:"Target,attr"` TargetMode string `xml:"TargetMode,attr,omitempty"`
TargetMode string `xml:"TargetMode,attr,omitempty"`
} }

55
structrel_test.go Normal file
View File

@@ -0,0 +1,55 @@
package docxlib
import (
"crypto/md5"
"encoding/hex"
"io"
"os"
"testing"
)
func TestRelationships(t *testing.T) {
rel := Relationships{
Xmlns: XMLNS_REL,
Relationship: []Relationship{
{
ID: "rId1",
Type: `http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles`,
Target: "styles.xml",
},
{
ID: "rId2",
Type: `http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme`,
Target: "theme/theme1.xml",
},
{
ID: "rId3",
Type: `http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable`,
Target: "fontTable.xml",
},
{
ID: "rId4",
Type: `http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings`,
Target: "settings.xml",
},
{
ID: "rId5",
Type: `http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings`,
Target: "webSettings.xml",
},
},
}
f, err := os.Create("TestRelationships.xml")
if err != nil {
t.Fatal(err)
}
h := md5.New()
_, err = io.Copy(io.MultiWriter(f, h), marshaller{data: &rel})
if err != nil {
t.Fatal(err)
}
m := hex.EncodeToString(h.Sum(make([]byte, 0, 16)))
if m != "c75af73ef6cc9536a193669c4a3605c3" {
t.Fatal("real md5:", m)
}
}

View File

@@ -3,6 +3,7 @@ package docxlib
import ( import (
"encoding/xml" "encoding/xml"
"io" "io"
"strings"
) )
// 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
@@ -36,19 +37,31 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
switch tt.Name.Local { switch tt.Name.Local {
case "rPr": case "rPr":
var value RunProperties var value RunProperties
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.RunProperties = &value r.RunProperties = &value
case "instrText": case "instrText":
var value string var value string
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.InstrText = value r.InstrText = value
case "t": case "t":
var value Text var value Text
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.Text = &value r.Text = &value
case "drawing": case "drawing":
var value Drawing var value Drawing
d.DecodeElement(&value, &tt) err = d.DecodeElement(&value, &tt)
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
return err
}
r.Drawing = &value r.Drawing = &value
case "tab": case "tab":
if r.InstrText == "" && r.Text == nil && r.Drawing == nil { if r.InstrText == "" && r.Text == nil && r.Drawing == nil {
@@ -159,6 +172,6 @@ type Size struct {
// both两端对齐。 // both两端对齐。
// distribute分散对齐。 // distribute分散对齐。
type Justification struct { type Justification struct {
XMLName xml.Name `xml:"w:jc"` // XMLName xml.Name `xml:"w:jc"`
Val string `xml:"w:val,attr"` Val string `xml:"w:val,attr"`
} }