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:
10
apipara.go
10
apipara.go
@@ -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
|
||||||
|
|||||||
11
empty.go
11
empty.go
@@ -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
12
link.go
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
2
pack.go
2
pack.go
@@ -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)
|
||||||
|
|||||||
80
structdoc.go
80
structdoc.go
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
120
structdrawing.go
120
structdrawing.go
@@ -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
82
structdrawing_test.go
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
17
structrel.go
17
structrel.go
@@ -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
55
structrel_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
25
structrun.go
25
structrun.go
@@ -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"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user