133 lines
4.1 KiB
Go
133 lines
4.1 KiB
Go
package processor
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"modify/processor/xpath"
|
|
"strings"
|
|
|
|
"github.com/antchfx/xmlquery"
|
|
lua "github.com/yuin/gopher-lua"
|
|
)
|
|
|
|
// XMLProcessor implements the Processor interface for XML documents
|
|
type XMLProcessor struct{}
|
|
|
|
// ProcessContent implements the Processor interface for XMLProcessor
|
|
func (p *XMLProcessor) ProcessContent(content string, path string, luaExpr string) (string, int, int, error) {
|
|
// Parse XML document
|
|
// We can't really use encoding/xml here because it requires a pre defined struct
|
|
// And we HAVE TO parse dynamic unknown XML
|
|
doc, err := xmlquery.Parse(strings.NewReader(content))
|
|
if err != nil {
|
|
return content, 0, 0, fmt.Errorf("error parsing XML: %v", err)
|
|
}
|
|
|
|
// Find nodes matching the XPath pattern
|
|
nodes, err := xpath.Get(doc, path)
|
|
if err != nil {
|
|
return content, 0, 0, fmt.Errorf("error executing XPath: %v", err)
|
|
}
|
|
|
|
matchCount := len(nodes)
|
|
if matchCount == 0 {
|
|
return content, 0, 0, nil
|
|
}
|
|
|
|
// Apply modifications to each node
|
|
modCount := 0
|
|
for _, node := range nodes {
|
|
L, err := NewLuaState()
|
|
if err != nil {
|
|
return content, 0, 0, fmt.Errorf("error creating Lua state: %v", err)
|
|
}
|
|
defer L.Close()
|
|
|
|
err = p.ToLua(L, node)
|
|
if err != nil {
|
|
return content, modCount, matchCount, fmt.Errorf("error converting to Lua: %v", err)
|
|
}
|
|
|
|
err = L.DoString(BuildLuaScript(luaExpr))
|
|
if err != nil {
|
|
return content, modCount, matchCount, fmt.Errorf("error executing Lua: %v", err)
|
|
}
|
|
|
|
result, err := p.FromLua(L)
|
|
if err != nil {
|
|
return content, modCount, matchCount, fmt.Errorf("error getting result from Lua: %v", err)
|
|
}
|
|
log.Printf("%#v", result)
|
|
|
|
// Apply modification
|
|
// if node.Type == xmlquery.AttributeNode {
|
|
// // For attribute nodes, update the attribute value
|
|
// node.Parent.Attr = append([]xmlquery.Attr{}, node.Parent.Attr...)
|
|
// for i, attr := range node.Parent.Attr {
|
|
// if attr.Name.Local == node.Data {
|
|
// node.Parent.Attr[i].Value = newValue
|
|
// break
|
|
// }
|
|
// }
|
|
// } else if node.Type == xmlquery.TextNode {
|
|
// // For text nodes, update the text content
|
|
// node.Data = newValue
|
|
// } else {
|
|
// // For element nodes, replace inner text
|
|
// // Simple approach: set the InnerText directly if there are no child elements
|
|
// if node.FirstChild == nil || (node.FirstChild != nil && node.FirstChild.Type == xmlquery.TextNode && node.FirstChild.NextSibling == nil) {
|
|
// if node.FirstChild != nil {
|
|
// node.FirstChild.Data = newValue
|
|
// } else {
|
|
// // Create a new text node and add it as the first child
|
|
// textNode := &xmlquery.Node{
|
|
// Type: xmlquery.TextNode,
|
|
// Data: newValue,
|
|
// }
|
|
// node.FirstChild = textNode
|
|
// }
|
|
// } else {
|
|
// // Complex case: node has mixed content or child elements
|
|
// // Replace just the text content while preserving child elements
|
|
// // This is a simplified approach - more complex XML may need more robust handling
|
|
// for child := node.FirstChild; child != nil; child = child.NextSibling {
|
|
// if child.Type == xmlquery.TextNode {
|
|
// child.Data = newValue
|
|
// break // Update only the first text node
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
modCount++
|
|
}
|
|
|
|
// Serialize the modified XML document to string
|
|
// if doc.FirstChild != nil && doc.FirstChild.Type == xmlquery.DeclarationNode {
|
|
// // If we have an XML declaration, start with it
|
|
// declaration := doc.FirstChild.OutputXML(true)
|
|
// // Remove the firstChild (declaration) before serializing the rest of the document
|
|
// doc.FirstChild = doc.FirstChild.NextSibling
|
|
// return declaration + doc.OutputXML(true), modCount, matchCount, nil
|
|
// }
|
|
|
|
// return doc.OutputXML(true), modCount, matchCount, nil
|
|
return "", modCount, matchCount, nil
|
|
}
|
|
|
|
// ToLua converts XML node values to Lua variables
|
|
func (p *XMLProcessor) ToLua(L *lua.LState, data interface{}) error {
|
|
table, err := ToLua(L, data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
L.SetGlobal("v", table)
|
|
return nil
|
|
}
|
|
|
|
// FromLua gets modified values from Lua
|
|
func (p *XMLProcessor) FromLua(L *lua.LState) (interface{}, error) {
|
|
luaValue := L.GetGlobal("v")
|
|
return FromLua(L, luaValue)
|
|
}
|