mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
a710bc5f41
commit
17a9a03361
2 files changed
+87
-38
No files matched your search
@@ -239,13 +239,19 @@ func (e *Editor) MoveDocumentContext(ctx context.Context, from, to int) error {
|
||||
return nil
|
||||
}
|
||||
return e.editDocumentsContext(ctx, func(reader *Reader, data []byte, root *editorXML) (int, error) {
|
||||
bodies := make([][]byte, reader.DocumentCount())
|
||||
for index := range bodies {
|
||||
nodes := make([]*editorXML, 0, reader.DocumentCount())
|
||||
bodies := make([][]byte, 0, reader.DocumentCount())
|
||||
for _, body := range root.children {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
body := root.childAt("DocBody", index)
|
||||
bodies[index] = data[body.start:body.end]
|
||||
if body.matchesOFD("DocBody") {
|
||||
nodes = append(nodes, body)
|
||||
bodies = append(bodies, data[body.start:body.end])
|
||||
}
|
||||
}
|
||||
if len(nodes) != reader.DocumentCount() {
|
||||
return 0, fmt.Errorf("document entry count mismatch")
|
||||
}
|
||||
moveEditorItem(bodies, from, to)
|
||||
var patches []editorXMLPatch
|
||||
@@ -253,7 +259,7 @@ func (e *Editor) MoveDocumentContext(ctx context.Context, from, to int) error {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
body := root.childAt("DocBody", index)
|
||||
body := nodes[index]
|
||||
patches = append(patches, editorXMLPatch{body.start, body.end, content})
|
||||
}
|
||||
reader.files["OFD.xml"] = editorPatchXML(data, patches)
|
||||
|
||||
+76
-33
@@ -16,7 +16,9 @@ package ofdgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -166,60 +168,101 @@ func parseVersionEntries(ctx context.Context, body *editorXML) ([]DocumentVersio
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// readDocumentVersionContext 读取版本描述,按描述文件位置解析清单和文档入口
|
||||
// readDocumentVersionContext 流式读取版本描述,按描述文件位置解析清单和文档入口
|
||||
// 入参: ctx 取消上下文, id 入口中的版本标识, location 描述文件路径
|
||||
// 返回: DocumentVersionInfo 版本信息, error 读取、描述或取消错误
|
||||
func (r *Reader) readDocumentVersionContext(ctx context.Context, id, location string) (DocumentVersionInfo, error) {
|
||||
var info DocumentVersionInfo
|
||||
data, err := r.readFileViewContext(ctx, location)
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
root, err := parseEditorXMLContext(ctx, data)
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
if root.name.Local != "DocVersion" || strings.TrimSpace(root.attr("ID")) != id {
|
||||
return info, fmt.Errorf("invalid version descriptor %s", location)
|
||||
}
|
||||
list, docRoot := root.child("FileList"), root.child("DocRoot")
|
||||
if list == nil || docRoot == nil {
|
||||
return info, fmt.Errorf("missing version FileList or DocRoot in %s", location)
|
||||
}
|
||||
if root.childAt("FileList", 1) != nil || root.childAt("DocRoot", 1) != nil {
|
||||
return info, fmt.Errorf("duplicate version FileList or DocRoot in %s", location)
|
||||
}
|
||||
entry, err := versionFileLocation(location, editorImportText(data, docRoot))
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
info = DocumentVersionInfo{ID: id, Location: location, Version: root.attr("Version"), Name: root.attr("Name"), CreationDate: root.attr("CreationDate"), DocRoot: entry}
|
||||
ids := map[string]bool{id: true}
|
||||
found := false
|
||||
for _, node := range list.children {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
if !node.matchesOFD("File") {
|
||||
input, err := r.openFile(location)
|
||||
if err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
defer input.Close()
|
||||
decoder := xml.NewDecoder(imageInput{ReadCloser: input, context: ctx})
|
||||
var info DocumentVersionInfo
|
||||
var root, parent *editorXML
|
||||
var files, entry bool
|
||||
ids := map[string]bool{id: true}
|
||||
for {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
token, err := decoder.Token()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
switch start := token.(type) {
|
||||
case xml.StartElement:
|
||||
node := &editorXML{name: start.Name, attrs: start.Attr, parent: parent}
|
||||
if parent == nil {
|
||||
if root != nil || start.Name.Local != "DocVersion" || strings.TrimSpace(node.attr("ID")) != id {
|
||||
return DocumentVersionInfo{}, fmt.Errorf("invalid version descriptor %s", location)
|
||||
}
|
||||
root, parent = node, node
|
||||
info = DocumentVersionInfo{ID: id, Location: location, Version: node.attr("Version"), Name: node.attr("Name"), CreationDate: node.attr("CreationDate")}
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case parent == root && node.matchesOFD("FileList"):
|
||||
if files {
|
||||
return DocumentVersionInfo{}, fmt.Errorf("duplicate version FileList in %s", location)
|
||||
}
|
||||
files, parent = true, node
|
||||
case parent == root && node.matchesOFD("DocRoot"):
|
||||
if entry {
|
||||
return DocumentVersionInfo{}, fmt.Errorf("duplicate version DocRoot in %s", location)
|
||||
}
|
||||
var value string
|
||||
if err := decoder.DecodeElement(&value, &start); err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
info.DocRoot, err = versionFileLocation(location, value)
|
||||
if err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
entry = true
|
||||
case parent != root && node.matchesOFD("File"):
|
||||
fileID := strings.TrimSpace(node.attr("ID"))
|
||||
if !ofdXMLIDValid(fileID) || ids[fileID] {
|
||||
return DocumentVersionInfo{}, fmt.Errorf("invalid or duplicate version file ID %q", fileID)
|
||||
}
|
||||
ids[fileID] = true
|
||||
name, err := versionFileLocation(location, editorImportText(data, node))
|
||||
var value string
|
||||
if err := decoder.DecodeElement(&value, &start); err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
name, err := versionFileLocation(location, value)
|
||||
if err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
found = found || name == entry
|
||||
info.Files = append(info.Files, VersionFile{ID: fileID, Location: name})
|
||||
default:
|
||||
if err := decoder.Skip(); err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
if !found {
|
||||
return DocumentVersionInfo{}, fmt.Errorf("version DocRoot absent from FileList: %s", entry)
|
||||
}
|
||||
case xml.EndElement:
|
||||
parent = parent.parent
|
||||
}
|
||||
}
|
||||
if !files || !entry {
|
||||
return DocumentVersionInfo{}, fmt.Errorf("missing version FileList or DocRoot in %s", location)
|
||||
}
|
||||
for _, file := range info.Files {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return DocumentVersionInfo{}, err
|
||||
}
|
||||
if file.Location == info.DocRoot {
|
||||
return info, nil
|
||||
}
|
||||
}
|
||||
return DocumentVersionInfo{}, fmt.Errorf("version DocRoot absent from FileList: %s", info.DocRoot)
|
||||
}
|
||||
|
||||
// versionFileLocation 解析版本描述中的ST_Loc,拒绝空路径和包外路径
|
||||
// 入参: owner 所在XML路径, value 引用路径
|
||||
|
||||
Reference in new issue
Block a user