Files
BigChef/processor/xml.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)
}