From 47b1957e72d818c9e4934842d02dc97c09ac2b5c Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Mon, 12 Oct 2026 12:18:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=8F=82=E7=85=A7=E6=A0=87=E5=87=86):=20?= =?UTF-8?q?=E8=A7=84=E8=8C=83=E5=85=83=E6=95=B0=E6=8D=AE=E4=B8=8E=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ofdgo_action.go | 122 ++++++++++++++++++++++++++++++++++++------------ ofdgo_doc.go | 79 ++++++++++++++++++++++++++++--- ofdgo_meta.go | 62 ++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 37 deletions(-) diff --git a/ofdgo_action.go b/ofdgo_action.go index 01bb0b9..06816a3 100644 --- a/ofdgo_action.go +++ b/ofdgo_action.go @@ -156,7 +156,51 @@ func decodeOFDActions(d *xml.Decoder, start xml.StartElement, actions *[]Action) }) } -// UnmarshalXML 解析跳转目标 +// UnmarshalXML 读取事件、区域和动作内容,忽略外部同名节点 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (action *Action) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *action = Action{Event: attrValue(start, "Event")} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + var target any + switch node.Name.Local { + case "Region": + target = &action.Region + case "Goto": + target = &action.Goto + case "URI": + target = &action.URI + case "GotoA": + target = &action.GotoA + case "Sound": + target = &action.Sound + case "Movie": + target = &action.Movie + default: + return d.Skip() + } + return d.DecodeElement(target, &node) + }) +} + +// UnmarshalXML 读取文档内跳转目标或书签,不采用外部扩展中的同名目标 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (action *Goto) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *action = Goto{} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + switch node.Name.Local { + case "Dest": + return d.DecodeElement(&action.Dest, &node) + case "Bookmark": + return d.DecodeElement(&action.Bookmark, &node) + default: + return d.Skip() + } + }) +} + +// UnmarshalXML 解析跳转目标,忽略外部坐标字段 // 入参: d XML解码器, start 起始节点 // 返回: error 错误信息 func (dest *Dest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { @@ -196,7 +240,24 @@ func (dest *Dest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { *target = v } } - if err := d.DecodeElement(&value, &start); err != nil { + if err := decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + var target **float64 + switch node.Name.Local { + case "Left": + target = &value.Left + case "Right": + target = &value.Right + case "Top": + target = &value.Top + case "Bottom": + target = &value.Bottom + case "Zoom": + target = &value.Zoom + default: + return d.Skip() + } + return d.DecodeElement(target, &node) + }); err != nil { return err } if value.Left != nil { @@ -231,6 +292,7 @@ func (dest *Dest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (m *Movie) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { type movie Movie value := movie{Operator: "Play"} + start = ofdXMLStart(start) if err := d.DecodeElement(&value, &start); err != nil { return err } @@ -238,39 +300,39 @@ func (m *Movie) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { return nil } -// UnmarshalXML 解析动作区域分路径并保留指令顺序 +// UnmarshalXML 读取动作区域中的OFD分路径,跳过外部扩展区域 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (region *Region) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *region = Region{} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local != "Area" { + return d.Skip() + } + return d.DecodeElement(®ion.Area, &node) + }) +} + +// UnmarshalXML 按原顺序读取区域指令,外部同名节点不参与路径绘制 // 入参: d XML解码器, start 起始节点 // 返回: error 错误信息 func (a *RegionArea) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { *a = RegionArea{Start: attrValue(start, "Start")} - for { - tok, err := d.Token() - if err != nil { - return err + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + command := RegionCommand{ + Type: node.Name.Local, + Point1: attrValue(node, "Point1"), + Point2: attrValue(node, "Point2"), + Point3: attrValue(node, "Point3"), + EllipseSize: attrValue(node, "EllipseSize"), + RotationAngle: attrValue(node, "RotationAngle"), + LargeArc: attrValue(node, "LargeArc"), + SweepDirection: attrValue(node, "SweepDirection"), + EndPoint: attrValue(node, "EndPoint"), } - switch node := tok.(type) { - case xml.StartElement: - command := RegionCommand{ - Type: node.Name.Local, - Point1: attrValue(node, "Point1"), - Point2: attrValue(node, "Point2"), - Point3: attrValue(node, "Point3"), - EllipseSize: attrValue(node, "EllipseSize"), - RotationAngle: attrValue(node, "RotationAngle"), - LargeArc: attrValue(node, "LargeArc"), - SweepDirection: attrValue(node, "SweepDirection"), - EndPoint: attrValue(node, "EndPoint"), - } - a.Command = append(a.Command, command) - if err := d.Skip(); err != nil { - return err - } - case xml.EndElement: - if node.Name.Local == start.Name.Local { - return nil - } - } - } + a.Command = append(a.Command, command) + return d.Skip() + }) } // gotoDest 获取文档内跳转目标 diff --git a/ofdgo_doc.go b/ofdgo_doc.go index eb628da..ad1a031 100644 --- a/ofdgo_doc.go +++ b/ofdgo_doc.go @@ -18,6 +18,7 @@ import ( "encoding/xml" "fmt" "path" + "strconv" "strings" ) @@ -388,17 +389,81 @@ func (a *Attachment) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error return nil } -// UnmarshalXML 解析大纲节点并应用默认值 +// UnmarshalXML 读取OFD书签列表,跳过外部同名条目 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (bookmarks *Bookmarks) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *bookmarks = Bookmarks{} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local != "Bookmark" { + return d.Skip() + } + return d.DecodeElement(&bookmarks.Bookmark, &node) + }) +} + +// UnmarshalXML 读取书签名称及目标,不使用外部扩展中的跳转信息 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (bookmark *Bookmark) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *bookmark = Bookmark{Name: attrValue(start, "Name")} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local != "Dest" { + return d.Skip() + } + return d.DecodeElement(&bookmark.Dest, &node) + }) +} + +// UnmarshalXML 读取OFD大纲列表,跳过外部同名节点 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (outlines *Outlines) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *outlines = Outlines{} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local != "OutlineElem" { + return d.Skip() + } + return d.DecodeElement(&outlines.OutlineElem, &node) + }) +} + +// UnmarshalXML 解析大纲节点、子大纲和动作,并应用默认展开状态 // 入参: d XML解码器, start 起始节点 // 返回: error 错误信息 func (o *OutlineElem) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { - type outlineElem OutlineElem - value := outlineElem{Expanded: true} - if err := d.DecodeElement(&value, &start); err != nil { - return err + *o = OutlineElem{Title: attrValue(start, "Title"), Expanded: true} + for _, attr := range start.Attr { + if attr.Name.Space != "" { + continue + } + value := strings.TrimSpace(attr.Value) + var err error + switch attr.Name.Local { + case "Count": + if value != "" { + o.Count, err = strconv.Atoi(value) + } + case "Expanded": + o.Expanded = false + if value != "" { + o.Expanded, err = strconv.ParseBool(value) + } + } + if err != nil { + return err + } } - *o = OutlineElem(value) - return nil + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + switch node.Name.Local { + case "Actions": + return decodeOFDActions(d, node, &o.Actions) + case "OutlineElem": + return d.DecodeElement(&o.OutlineElem, &node) + default: + return d.Skip() + } + }) } // UnmarshalXML 解析文档权限并应用默认值 diff --git a/ofdgo_meta.go b/ofdgo_meta.go index 7cf62e9..3c7c4c0 100644 --- a/ofdgo_meta.go +++ b/ofdgo_meta.go @@ -106,3 +106,65 @@ func (body *DocBody) UnmarshalXML(decoder *xml.Decoder, start xml.StartElement) return d.Skip() }) } + +// UnmarshalXML 读取文档元数据,不将外部同名字段作为OFD信息 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (info *DocInfo) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *info = DocInfo{} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + var target any + switch node.Name.Local { + case "DocID": + target = &info.DocID + case "Title": + target = &info.Title + case "Author": + target = &info.Author + case "Subject": + target = &info.Subject + case "Abstract": + target = &info.Abstract + case "CreationDate": + target = &info.CreationDate + case "ModDate": + target = &info.ModDate + case "Creator": + target = &info.Creator + case "CreatorVersion": + target = &info.CreatorVersion + case "CustomDatas": + target = &info.CustomDatas + default: + return d.Skip() + } + return d.DecodeElement(target, &node) + }) +} + +// UnmarshalXML 按原顺序读取OFD自定义字段,跳过外部扩展条目 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (data *CustomDatas) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + *data = CustomDatas{} + return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error { + if node.Name.Local != "CustomData" { + return d.Skip() + } + return d.DecodeElement(&data.CustomData, &node) + }) +} + +// UnmarshalXML 读取自定义字段的名称和文本,忽略带命名空间的属性 +// 入参: d XML解码器, start 起始节点 +// 返回: error 解析错误 +func (data *CustomData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type customData CustomData + var value customData + start = ofdXMLStart(start) + if err := d.DecodeElement(&value, &start); err != nil { + return err + } + *data = CustomData(value) + return nil +}