mirror of
https://github.com/fumiama/go-docx.git
synced 2026-06-05 07:40:24 +08:00
初步添加shape
This commit is contained in:
8
empty.go
8
empty.go
@@ -31,9 +31,11 @@ func newEmptyA4File() *Docx {
|
||||
XMLName: xml.Name{
|
||||
Space: "w",
|
||||
},
|
||||
XMLW: XMLNS_W,
|
||||
XMLR: XMLNS_R,
|
||||
XMLWP: XMLNS_WP,
|
||||
XMLW: XMLNS_W,
|
||||
XMLR: XMLNS_R,
|
||||
XMLWP: XMLNS_WP,
|
||||
XMLWPS: XMLNS_WPS,
|
||||
// XMLMC: XMLNS_MC,
|
||||
// XMLWP14: XMLNS_WP14,
|
||||
Body: Body{
|
||||
Items: make([]interface{}, 0, 64),
|
||||
|
||||
16
structdoc.go
16
structdoc.go
@@ -28,9 +28,11 @@ import (
|
||||
|
||||
//nolint:revive,stylecheck
|
||||
const (
|
||||
XMLNS_W = `http://schemas.openxmlformats.org/wordprocessingml/2006/main`
|
||||
XMLNS_R = `http://schemas.openxmlformats.org/officeDocument/2006/relationships`
|
||||
XMLNS_WP = `http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing`
|
||||
XMLNS_W = `http://schemas.openxmlformats.org/wordprocessingml/2006/main`
|
||||
XMLNS_R = `http://schemas.openxmlformats.org/officeDocument/2006/relationships`
|
||||
XMLNS_WP = `http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing`
|
||||
XMLNS_WPS = `http://schemas.microsoft.com/office/word/2010/wordprocessingShape`
|
||||
// XMLNS_MC = `http://schemas.openxmlformats.org/markup-compatibility/2006`
|
||||
// XMLNS_WP14 = `http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing`
|
||||
|
||||
XMLNS_PICTURE = `http://schemas.openxmlformats.org/drawingml/2006/picture`
|
||||
@@ -95,9 +97,11 @@ func (b *Body) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
// Document <w:document>
|
||||
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
|
||||
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
|
||||
XMLWPS string `xml:"xmlns:wps,attr,omitempty"` // cannot be unmarshalled in
|
||||
// XMLMC string `xml:"xmlns:mc,attr,omitempty"` // cannot be unmarshalled in
|
||||
// XMLWP14 string `xml:"xmlns:wp14,attr,omitempty"` // cannot be unmarshalled in
|
||||
|
||||
Body Body `xml:"w:body"`
|
||||
|
||||
@@ -741,10 +741,6 @@ func (p *PICSpPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
return err
|
||||
}
|
||||
case "prstGeom":
|
||||
err = d.DecodeElement(&p.PrstGeom, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
p.PrstGeom.Prst = getAtt(tt.Attr, "prst")
|
||||
default:
|
||||
err = d.Skip() // skip unsupported tags
|
||||
|
||||
120
structrun.go
120
structrun.go
@@ -49,56 +49,92 @@ func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var child interface{}
|
||||
|
||||
if tt, ok := t.(xml.StartElement); ok {
|
||||
switch tt.Name.Local {
|
||||
case "rPr":
|
||||
var value RunProperties
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
r.RunProperties = &value
|
||||
continue
|
||||
case "instrText":
|
||||
var value string
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
r.InstrText = value
|
||||
continue
|
||||
case "t":
|
||||
var value Text
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
child = &value
|
||||
case "drawing":
|
||||
var value Drawing
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
child = &value
|
||||
case "tab":
|
||||
child = &Tab{}
|
||||
default:
|
||||
err = d.Skip() // skip unsupported tags
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
child, err := r.parse(d, tt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if child != nil {
|
||||
r.Children = append(r.Children, child)
|
||||
}
|
||||
r.Children = append(r.Children, child)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Run) parse(d *xml.Decoder, tt xml.StartElement) (child interface{}, err error) {
|
||||
switch tt.Name.Local {
|
||||
case "rPr":
|
||||
var value RunProperties
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return nil, err
|
||||
}
|
||||
r.RunProperties = &value
|
||||
return nil, nil
|
||||
case "instrText":
|
||||
var value string
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return nil, err
|
||||
}
|
||||
r.InstrText = value
|
||||
return nil, nil
|
||||
case "t":
|
||||
var value Text
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return nil, err
|
||||
}
|
||||
child = &value
|
||||
case "drawing":
|
||||
var value Drawing
|
||||
err = d.DecodeElement(&value, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return nil, err
|
||||
}
|
||||
child = &value
|
||||
case "tab":
|
||||
child = &Tab{}
|
||||
case "AlternateContent":
|
||||
altcont:
|
||||
for {
|
||||
tok, err1 := d.Token()
|
||||
if err1 == io.EOF {
|
||||
break
|
||||
}
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
|
||||
if ttt, ok := tok.(xml.StartElement); ok && ttt.Name.Local == "Choice" {
|
||||
for _, attr := range ttt.Attr {
|
||||
if attr.Name.Local == "Requires" {
|
||||
if attr.Value == "wps" {
|
||||
child, err = r.parse(d, ttt)
|
||||
break altcont
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if et, ok := tok.(xml.EndElement); ok {
|
||||
if et.Name.Local == "AlternateContent" {
|
||||
break
|
||||
}
|
||||
}
|
||||
err = d.Skip() // skip unsupported tags
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
default:
|
||||
err = d.Skip() // skip unsupported tags
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RunProperties encapsulates visual properties of a run
|
||||
type RunProperties struct {
|
||||
XMLName xml.Name `xml:"w:rPr,omitempty"`
|
||||
|
||||
263
structshape.go
Normal file
263
structshape.go
Normal file
@@ -0,0 +1,263 @@
|
||||
package docx
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// WPSWordprocessingShape is a container for a WordprocessingML DrawingML shape.
|
||||
type WPSWordprocessingShape struct {
|
||||
XMLName xml.Name `xml:"wps:wsp,omitempty"`
|
||||
CNvCnPr *WPSCNvCnPr
|
||||
SpPr *WPSSpPr
|
||||
BodyPr *WPSBodyPr
|
||||
}
|
||||
|
||||
// UnmarshalXML ...
|
||||
func (w *WPSWordprocessingShape) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
for {
|
||||
t, err := d.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tt, ok := t.(xml.StartElement); ok {
|
||||
switch tt.Name.Local {
|
||||
case "cNvCnPr":
|
||||
w.CNvCnPr = new(WPSCNvCnPr)
|
||||
err = d.DecodeElement(w.CNvCnPr, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
case "spPr":
|
||||
w.SpPr = new(WPSSpPr)
|
||||
err = d.DecodeElement(w.SpPr, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
case "bodyPr":
|
||||
w.BodyPr = new(WPSBodyPr)
|
||||
err = d.DecodeElement(w.BodyPr, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
err = d.Skip() // skip unsupported tags
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WPSCNvCnPr represents the non-visual drawing properties of a connector.
|
||||
type WPSCNvCnPr struct {
|
||||
XMLName xml.Name `xml:"wps:cNvCnPr,omitempty"`
|
||||
ConnShapeLocks *struct{} `xml:"a:cxnSpLocks,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalXML ...
|
||||
func (w *WPSCNvCnPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
for {
|
||||
t, err := d.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tt, ok := t.(xml.StartElement); ok {
|
||||
switch tt.Name.Local {
|
||||
case "cxnSpLocks":
|
||||
w.ConnShapeLocks = &struct{}{}
|
||||
default:
|
||||
err = d.Skip() // skip unsupported tags
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WPSSpPr is a container element that represents the visual properties of a shape.
|
||||
type WPSSpPr struct {
|
||||
XMLName xml.Name `xml:"wps:spPr,omitempty"`
|
||||
BWMode string `xml:"bwMode,attr"`
|
||||
|
||||
Xfrm AXfrm
|
||||
PrstGeom APrstGeom
|
||||
NoFill *struct{} `xml:"a:noFill,omitempty"`
|
||||
Ln *ALine
|
||||
}
|
||||
|
||||
// UnmarshalXML ...
|
||||
func (w *WPSSpPr) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
for _, attr := range start.Attr {
|
||||
switch attr.Name.Local {
|
||||
case "bwMode":
|
||||
w.BWMode = attr.Value
|
||||
default:
|
||||
// ignore other attributes
|
||||
}
|
||||
}
|
||||
for {
|
||||
t, err := d.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tt, ok := t.(xml.StartElement); ok {
|
||||
switch tt.Name.Local {
|
||||
case "xfrm":
|
||||
err = d.DecodeElement(&w.Xfrm, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
case "prstGeom":
|
||||
w.PrstGeom.Prst = getAtt(tt.Attr, "prst")
|
||||
case "noFill":
|
||||
w.NoFill = &struct{}{}
|
||||
case "ln":
|
||||
w.Ln = &ALine{}
|
||||
err = d.DecodeElement(&w.Ln, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
err = d.Skip() // skip unsupported tags
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ALine represents a line element in a Word document.
|
||||
type ALine struct {
|
||||
XMLName xml.Name `xml:"a:ln,omitempty"`
|
||||
W int64 `xml:"w,attr"`
|
||||
|
||||
SolidFill *ASolidFill
|
||||
Round *struct{} `xml:"a:round,omitempty"`
|
||||
HeadEnd *struct{} `xml:"a:headEnd,omitempty"`
|
||||
TailEnd *struct{} `xml:"a:tailEnd,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalXML ...
|
||||
func (l *ALine) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
|
||||
for _, attr := range start.Attr {
|
||||
switch attr.Name.Local {
|
||||
case "w":
|
||||
l.W, err = strconv.ParseInt(attr.Value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
// ignore other attributes
|
||||
}
|
||||
}
|
||||
for {
|
||||
t, err := d.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tt, ok := t.(xml.StartElement); ok {
|
||||
switch tt.Name.Local {
|
||||
case "solidFill":
|
||||
l.SolidFill = new(ASolidFill)
|
||||
err = d.DecodeElement(l.SolidFill, &tt)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "expected") {
|
||||
return err
|
||||
}
|
||||
case "round":
|
||||
l.Round = &struct{}{}
|
||||
case "headEnd":
|
||||
l.HeadEnd = &struct{}{}
|
||||
case "tailEnd":
|
||||
l.TailEnd = &struct{}{}
|
||||
default:
|
||||
err = d.Skip() // skip unsupported tags
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ASolidFill represents a solid fill of a shape or chart element.
|
||||
type ASolidFill struct {
|
||||
XMLName xml.Name `xml:"a:solidFill,omitempty"`
|
||||
SrgbClr *ASrgbClr
|
||||
}
|
||||
|
||||
// UnmarshalXML ...
|
||||
func (s *ASolidFill) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
for {
|
||||
t, err := d.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tt, ok := t.(xml.StartElement); ok {
|
||||
switch tt.Name.Local {
|
||||
case "srgbClr":
|
||||
s.SrgbClr = new(ASrgbClr)
|
||||
for _, attr := range tt.Attr {
|
||||
if attr.Name.Local == "val" {
|
||||
s.SrgbClr.Val = attr.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
err = d.Skip() // skip unsupported elements
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
err = d.Skip() // skip unsupported elements
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ASrgbClr represents an sRGB color.
|
||||
type ASrgbClr struct {
|
||||
XMLName xml.Name `xml:"a:srgbClr,omitempty"`
|
||||
Val string `xml:"val,attr"`
|
||||
}
|
||||
|
||||
// WPSBodyPr represents the body properties for a WordprocessingML DrawingML shape.
|
||||
type WPSBodyPr struct {
|
||||
XMLName xml.Name `xml:"wps:bodyPr,omitempty"`
|
||||
}
|
||||
@@ -81,6 +81,8 @@ func (f *Docx) parseDocument(file *zip.File) error {
|
||||
f.Document.XMLW = XMLNS_W
|
||||
f.Document.XMLR = XMLNS_R
|
||||
f.Document.XMLWP = XMLNS_WP
|
||||
// f.Document.XMLMC = XMLNS_MC
|
||||
f.Document.XMLWPS = XMLNS_WPS
|
||||
// f.Document.XMLWP14 = XMLNS_WP14
|
||||
f.Document.XMLName.Space = XMLNS_W
|
||||
f.Document.XMLName.Local = "document"
|
||||
|
||||
Reference in New Issue
Block a user