Integrate the xml processing with the rest of the project
This commit is contained in:
147
processor/xml.go
147
processor/xml.go
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
|
||||
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
)
|
||||
|
||||
var xmlLogger = logger.Default.WithPrefix("processor/xml")
|
||||
@@ -445,3 +446,149 @@ func formatNumeric(f float64) string {
|
||||
}
|
||||
return strconv.FormatFloat(f, 'f', -1, 64)
|
||||
}
|
||||
|
||||
// ProcessXML applies Lua processing to XML content with surgical editing
|
||||
func ProcessXML(content string, command utils.ModifyCommand, filename string) ([]utils.ReplaceCommand, error) {
|
||||
processXMLLogger := xmlLogger.WithPrefix("ProcessXML").WithField("commandName", command.Name).WithField("file", filename)
|
||||
processXMLLogger.Debug("Starting XML processing for file")
|
||||
|
||||
// Parse XML with position tracking
|
||||
originalElem, err := parseXMLWithPositions(content)
|
||||
if err != nil {
|
||||
processXMLLogger.Error("Failed to parse XML: %v", err)
|
||||
return nil, fmt.Errorf("failed to parse XML: %v", err)
|
||||
}
|
||||
processXMLLogger.Debug("Successfully parsed XML content")
|
||||
|
||||
// Create Lua state
|
||||
L, err := NewLuaState()
|
||||
if err != nil {
|
||||
processXMLLogger.Error("Error creating Lua state: %v", err)
|
||||
return nil, fmt.Errorf("error creating Lua state: %v", err)
|
||||
}
|
||||
defer L.Close()
|
||||
|
||||
// Set filename global
|
||||
L.SetGlobal("file", lua.LString(filename))
|
||||
|
||||
// Create modifiable copy
|
||||
modifiedElem := deepCopyXMLElement(originalElem)
|
||||
|
||||
// Convert to Lua table and set as global
|
||||
luaTable := xmlElementToLuaTable(L, modifiedElem)
|
||||
L.SetGlobal("root", luaTable)
|
||||
processXMLLogger.Debug("Set XML data as Lua global 'root'")
|
||||
|
||||
// Build and execute Lua script
|
||||
luaExpr := BuildJSONLuaScript(command.Lua) // Reuse JSON script builder
|
||||
processXMLLogger.Debug("Built Lua script from expression: %q", command.Lua)
|
||||
|
||||
if err := L.DoString(luaExpr); err != nil {
|
||||
processXMLLogger.Error("Lua script execution failed: %v\nScript: %s", err, luaExpr)
|
||||
return nil, fmt.Errorf("lua script execution failed: %v", err)
|
||||
}
|
||||
processXMLLogger.Debug("Lua script executed successfully")
|
||||
|
||||
// Check if modification flag is set
|
||||
modifiedVal := L.GetGlobal("modified")
|
||||
if modifiedVal.Type() != lua.LTBool || !lua.LVAsBool(modifiedVal) {
|
||||
processXMLLogger.Debug("Skipping - no modifications indicated by Lua script")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Get the modified data back from Lua
|
||||
modifiedTable := L.GetGlobal("root")
|
||||
if modifiedTable.Type() != lua.LTTable {
|
||||
processXMLLogger.Error("Expected 'root' to be a table after Lua processing")
|
||||
return nil, fmt.Errorf("expected 'root' to be a table after Lua processing")
|
||||
}
|
||||
|
||||
// Apply Lua modifications back to XMLElement
|
||||
luaTableToXMLElement(L, modifiedTable.(*lua.LTable), modifiedElem)
|
||||
|
||||
// Find changes between original and modified
|
||||
changes := findXMLChanges(originalElem, modifiedElem, "")
|
||||
processXMLLogger.Debug("Found %d changes", len(changes))
|
||||
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Generate surgical replace commands
|
||||
commands := applyXMLChanges(changes)
|
||||
processXMLLogger.Debug("Generated %d replace commands", len(commands))
|
||||
|
||||
return commands, nil
|
||||
}
|
||||
|
||||
// xmlElementToLuaTable converts an XMLElement to a Lua table
|
||||
func xmlElementToLuaTable(L *lua.LState, elem *XMLElement) *lua.LTable {
|
||||
table := L.CreateTable(0, 4)
|
||||
table.RawSetString("_tag", lua.LString(elem.Tag))
|
||||
|
||||
if len(elem.Attributes) > 0 {
|
||||
attrs := L.CreateTable(0, len(elem.Attributes))
|
||||
for name, attr := range elem.Attributes {
|
||||
attrs.RawSetString(name, lua.LString(attr.Value))
|
||||
}
|
||||
table.RawSetString("_attr", attrs)
|
||||
}
|
||||
|
||||
if elem.Text != "" {
|
||||
table.RawSetString("_text", lua.LString(elem.Text))
|
||||
}
|
||||
|
||||
if len(elem.Children) > 0 {
|
||||
children := L.CreateTable(len(elem.Children), 0)
|
||||
for i, child := range elem.Children {
|
||||
children.RawSetInt(i+1, xmlElementToLuaTable(L, child))
|
||||
}
|
||||
table.RawSetString("_children", children)
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
// luaTableToXMLElement applies Lua table modifications back to XMLElement
|
||||
func luaTableToXMLElement(L *lua.LState, table *lua.LTable, elem *XMLElement) {
|
||||
// Update text
|
||||
if textVal := table.RawGetString("_text"); textVal.Type() == lua.LTString {
|
||||
elem.Text = string(textVal.(lua.LString))
|
||||
}
|
||||
|
||||
// Update attributes
|
||||
if attrVal := table.RawGetString("_attr"); attrVal.Type() == lua.LTTable {
|
||||
attrTable := attrVal.(*lua.LTable)
|
||||
// Clear and rebuild attributes
|
||||
elem.Attributes = make(map[string]XMLAttribute)
|
||||
attrTable.ForEach(func(key lua.LValue, value lua.LValue) {
|
||||
if key.Type() == lua.LTString && value.Type() == lua.LTString {
|
||||
attrName := string(key.(lua.LString))
|
||||
attrValue := string(value.(lua.LString))
|
||||
elem.Attributes[attrName] = XMLAttribute{Value: attrValue}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Update children
|
||||
if childrenVal := table.RawGetString("_children"); childrenVal.Type() == lua.LTTable {
|
||||
childrenTable := childrenVal.(*lua.LTable)
|
||||
newChildren := []*XMLElement{}
|
||||
|
||||
// Iterate over array indices
|
||||
for i := 1; ; i++ {
|
||||
childVal := childrenTable.RawGetInt(i)
|
||||
if childVal.Type() == lua.LTNil {
|
||||
break
|
||||
}
|
||||
if childVal.Type() == lua.LTTable {
|
||||
if i-1 < len(elem.Children) {
|
||||
// Update existing child
|
||||
luaTableToXMLElement(L, childVal.(*lua.LTable), elem.Children[i-1])
|
||||
newChildren = append(newChildren, elem.Children[i-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
elem.Children = newChildren
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user