Skip to content

Commit

Permalink
Optimize template replacement speed (#34)
Browse files Browse the repository at this point in the history
* Optimize template replacement speed
* xmlNode data struct change(child data struct change from slice to doubly linked list)
* Template.expandPlaceholders(xnode *xmlNode) ,Template.replaceSingleParams(xnode *xmlNode, triggerParamOnly bool)method refactoring
  • Loading branch information
0fv authored Jul 3, 2024
1 parent 26ed7dd commit 419186a
Show file tree
Hide file tree
Showing 6 changed files with 391 additions and 284 deletions.
16 changes: 9 additions & 7 deletions ImageProcesser.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,20 @@ func processImage(img *Image) (imgXMLStr string, err error) {
imgExt := strings.TrimLeft(strings.ToLower(path.Ext(imgPath)), ".")
contentTypesName := "[Content_Types].xml"
contentTypesNode := t.fileToXMLStruct(contentTypesName)
for _, node := range contentTypesNode.Nodes {
contentTypesNode.iterate(func(node *xmlNode) bool {
if strings.ToLower(node.Attr("Extension")) == imgExt {
isContainType = true
return true
}
}
return false
})
if !isContainType {
contentTypesNode.Nodes = append(contentTypesNode.Nodes, &xmlNode{
contentTypesNode.addSub(&xmlNode{
XMLName: xml.Name{
Space: "",
Local: "Default",
},
Attrs: []*xml.Attr{
Attrs: []xml.Attr{
{Name: xml.Name{Space: "", Local: "Extension"}, Value: imgExt},
{Name: xml.Name{Space: "", Local: "ContentType"}, Value: "image/" + imgExt},
},
Expand All @@ -70,13 +72,13 @@ func processImage(img *Image) (imgXMLStr string, err error) {
} else {
relNode = t.fileToXMLStruct(relName)
}
rid := fmt.Sprintf("rId%d", len(relNode.Nodes)+1)
relNode.Nodes = append(relNode.Nodes, &xmlNode{
rid := fmt.Sprintf("rId%d", relNode.childLenght+1)
relNode.addSub(&xmlNode{
XMLName: xml.Name{
Space: "",
Local: "Relationship",
},
Attrs: []*xml.Attr{
Attrs: []xml.Attr{
{Name: xml.Name{Space: "", Local: "Id"}, Value: rid},
{Name: xml.Name{Space: "", Local: "Type"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"},
{Name: xml.Name{Space: "", Local: "Target"}, Value: "media/" + imgPath},
Expand Down
12 changes: 6 additions & 6 deletions Param.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type Param struct {
Trigger *ParamTrigger

RowPlaceholder string
Index int //slice data index,expandPlaceholders function needs
}

// NewParam ..
Expand Down Expand Up @@ -238,7 +239,7 @@ func (p *Param) RunTrigger(xnode *xmlNode) {
}

n := xnode.closestUp(ntypes)
if n == nil || n.isDeleted {
if n == nil {
// aurora.Red("EMPTY parent of %v", xnode.Tag())
return
}
Expand All @@ -250,24 +251,23 @@ func (p *Param) RunTrigger(xnode *xmlNode) {
isListRemove = isListRemove || (isListItem && p.Trigger.Scope == TriggerScopeSection) // :section
if isListRemove && isListItem {
// find all list items as this
for _, wpNode := range n.parent.Nodes {
n.parent.childFirst.iterate(func(wpNode *xmlNode) bool {
isitem, listid := wpNode.IsListItem()
if !isitem || listid != listID {
// aurora.Red("--- %s [%s]", wpNode, wpNode.AllContents())
continue
return false
}
if p.Trigger.Command == TriggerCommandRemove {
wpNode.Nodes = nil
wpNode.delete()
}
}
return false
})
return
}

// Simple cases
if p.Trigger.Command == TriggerCommandRemove {
// fmt.Printf("Trigger: [%s] [%s]\t Command=[%s]\n", aurora.Blue(p.AbsoluteKey), aurora.Magenta(p.Trigger.String()), aurora.BgMagenta(p.Trigger.Command))
n.Nodes = nil
n.delete()
return
}
Expand Down
61 changes: 61 additions & 0 deletions ParamList.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"log"
"reflect"
"regexp"
"strings"
)

// ParamList ..
Expand Down Expand Up @@ -244,3 +245,63 @@ func (params ParamList) Walk(fn func(*Param)) {
p.Walk(fn, p.Level+1)
}
}

func (params ParamList) WalkWithEnd(fn func(*Param) bool) {
for _, p := range params {
if fn(p) {
continue
}
p.Params.WalkWithEnd(fn)
}
}

func (p ParamList) FindAllByKey(key string) []*Param {
keySlice := strings.Split(key, ".")
var ret []*Param
p.findAllByKey(nil, nil, 0, 1, keySlice, &ret)
return ret
}

func (p ParamList) findAllByKey(privParamList, paramList []int, offset, depth int, key []string, params *[]*Param) ([]int, int) {
if depth > len(key) {
return nil, 0
}
currLev := strings.Join(key[:depth], ".")
for i, param := range p {
curr := make([]int, len(paramList))
copy(curr, paramList)
if param.parent != nil && param.parent.Type == SliceParam {
curr = append(curr, i+1)
}
if param.Type == StructParam {
privParamList, offset = param.Params.findAllByKey(privParamList, curr, offset, depth+1, key, params)
} else {
if param.CompactKey == currLev || param.AbsoluteKey == currLev {
if param.Type == SliceParam {
privParamList, offset = param.Params.findAllByKey(privParamList, curr, offset, depth, key, params)
continue
}
if depth == len(key) {
index := 1
if len(curr) > 0 {
index = curr[len(curr)-1]
if len(curr) == len(privParamList) {
for i := range curr[:len(curr)-1] {
if privParamList[i] != curr[i] {
offset += privParamList[len(privParamList)-1]
break
}
}
}
}
param.Index = index + offset
privParamList = curr
*params = append(*params, param)
} else {
privParamList, offset = param.Params.findAllByKey(privParamList, curr, offset, depth+1, key, params)
}
}
}
}
return privParamList, offset
}
44 changes: 19 additions & 25 deletions Template.helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (t *Template) bytesToXMLStruct(buf []byte) *xmlNode {
buf = bytes.ReplaceAll(buf, []byte("</v:"), []byte("</v-"))

xdocNode := &xmlNode{}
if err := xml.Unmarshal(buf, &xdocNode); err != nil {
if err := xml.Unmarshal(buf, xdocNode); err != nil {
log.Printf("fileToXMLStruct: %v", err)
}

Expand All @@ -29,10 +29,13 @@ func (t *Template) bytesToXMLStruct(buf []byte) *xmlNode {
if xnode.Tag() == "w-body" {
xnode.parent = xdocNode
}

for _, n := range xnode.Nodes {
n.parent = xnode
if xnode.childFirst != nil {
xnode.childFirst.iterate(func(node *xmlNode) bool {
node.parent = xnode
return false
})
}

})

// log.Printf("%s", structToXMLBytes(n))
Expand Down Expand Up @@ -71,13 +74,13 @@ func (t *Template) replaceImageParams(xnode *xmlNode, param *Param) {
parent: xnode.parent,
isNew: true,
}
xnode.parent.Nodes = append(xnode.parent.Nodes, contentNode)
xnode.add(contentNode)
}
// image node
if len(contentSlice)-i > 1 {
imgNode := t.bytesToXMLStruct([]byte(param.Value))
imgNode.parent = xnode.parent
xnode.parent.Nodes = append(xnode.parent.Nodes, imgNode)
xnode.add(imgNode)
}
}
// Empty the content before deleting to prevent reprocessing when params walk
Expand Down Expand Up @@ -121,32 +124,23 @@ func (t *Template) matchBrokenRightPlaceholder(content string) bool {
return t.matchBrokenPlaceholder(content, false)
}

func (t Template) GetContentPrefixList(content []byte) []string {
func (t Template) GetAttrParam(attr string) []string {
var ret []string
var record strings.Builder
start := false
length := len(content)
for i, v := range content {
if i == 0 {
continue
}

if v == '{' && content[i-1] == '{' {
length := len(attr)
for i := 1; i < length-1; i++ {
if attr[i] == '{' && attr[i-1] == '{' {
start = true
continue
}
if start && (attr[i] == ' ' || (attr[i] == '}' && length-1 > i && attr[i+1] == '}')) {
ret = append(ret, record.String())
record.Reset()
start = false
}
if start {
if v == ' ' || (v == '}' && length-1 > i && content[i+1] == '}') {
ret = append(ret, record.String())
record.Reset()
start = false
}
if v == '.' {
ret = append(ret, record.String())
record.Reset()
continue
}
record.WriteByte(v)
record.WriteByte(attr[i])
}
}
return ret
Expand Down
Loading

0 comments on commit 419186a

Please sign in to comment.