added code
This commit is contained in:
230
xml_extractor.py
Normal file
230
xml_extractor.py
Normal file
@@ -0,0 +1,230 @@
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog, messagebox, ttk
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
|
||||
class XMLExtractorApp:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.root.title("XML Shape to Symbol Extractor")
|
||||
self.root.geometry("600x600")
|
||||
self.root.resizable(False, False)
|
||||
|
||||
self.input_file = None
|
||||
self.tree = None
|
||||
|
||||
self.create_widgets()
|
||||
|
||||
def create_widgets(self):
|
||||
# Title
|
||||
title = tk.Label(self.root, text="XML Shape to Symbol Extractor",
|
||||
font=("Arial", 16, "bold"))
|
||||
title.pack(pady=10)
|
||||
|
||||
# Info label
|
||||
info = tk.Label(self.root, text="Extracts from: /layers/layer/shape\nWrites to: /key/kentry/custom/symbol/group/shape",
|
||||
font=("Arial", 9), fg="gray", justify=tk.CENTER)
|
||||
info.pack()
|
||||
|
||||
# Input file frame
|
||||
input_frame = tk.Frame(self.root)
|
||||
input_frame.pack(pady=10, padx=20, fill=tk.X)
|
||||
|
||||
tk.Label(input_frame, text="Input LXXPLOT File:",
|
||||
font=("Arial", 10)).pack(anchor=tk.W)
|
||||
|
||||
file_display_frame = tk.Frame(input_frame)
|
||||
file_display_frame.pack(fill=tk.X, pady=5)
|
||||
|
||||
self.file_label = tk.Label(file_display_frame, text="No file selected",
|
||||
fg="gray", anchor=tk.W)
|
||||
self.file_label.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
|
||||
browse_btn = tk.Button(file_display_frame, text="Browse",
|
||||
command=self.browse_file)
|
||||
browse_btn.pack(side=tk.RIGHT)
|
||||
|
||||
# Output file frame
|
||||
output_frame = tk.Frame(self.root)
|
||||
output_frame.pack(pady=10, padx=20, fill=tk.X)
|
||||
|
||||
tk.Label(output_frame, text="Output LXKEY File:",
|
||||
font=("Arial", 10)).pack(anchor=tk.W)
|
||||
|
||||
self.output_entry = tk.Entry(output_frame, font=("Arial", 10))
|
||||
self.output_entry.pack(fill=tk.X, pady=5)
|
||||
self.output_entry.insert(0, "symbol_output.lxkey")
|
||||
|
||||
# Additional fields frame
|
||||
fields_frame = tk.Frame(self.root)
|
||||
fields_frame.pack(pady=10, padx=20, fill=tk.X)
|
||||
|
||||
tk.Label(fields_frame, text="Additional Tag Values:",
|
||||
font=("Arial", 10, "bold")).pack(anchor=tk.W, pady=(0, 5))
|
||||
|
||||
# Name field (displayed as "Type")
|
||||
name_frame = tk.Frame(fields_frame)
|
||||
name_frame.pack(fill=tk.X, pady=2)
|
||||
tk.Label(name_frame, text="Type:", width=10, anchor=tk.W).pack(side=tk.LEFT)
|
||||
self.name_entry = tk.Entry(name_frame, font=("Arial", 10))
|
||||
self.name_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
|
||||
# ID field
|
||||
id_frame = tk.Frame(fields_frame)
|
||||
id_frame.pack(fill=tk.X, pady=2)
|
||||
tk.Label(id_frame, text="ID:", width=10, anchor=tk.W).pack(side=tk.LEFT)
|
||||
self.id_entry = tk.Entry(id_frame, font=("Arial", 10))
|
||||
self.id_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
|
||||
# Fname field
|
||||
fname_frame = tk.Frame(fields_frame)
|
||||
fname_frame.pack(fill=tk.X, pady=2)
|
||||
tk.Label(fname_frame, text="Fname:", width=10, anchor=tk.W).pack(side=tk.LEFT)
|
||||
self.fname_entry = tk.Entry(fname_frame, font=("Arial", 10))
|
||||
self.fname_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
|
||||
# Kind field (dropdown)
|
||||
kind_frame = tk.Frame(fields_frame)
|
||||
kind_frame.pack(fill=tk.X, pady=2)
|
||||
tk.Label(kind_frame, text="Kind:", width=10, anchor=tk.W).pack(side=tk.LEFT)
|
||||
|
||||
# Dictionary mapping display names to values
|
||||
self.kind_options = {
|
||||
"eko / ERS": "ers",
|
||||
"Zoom Leko / ERS": "zers",
|
||||
"Fresnel / PC": "fres",
|
||||
"PAR": "par",
|
||||
"Flood": "fl",
|
||||
"Striplight": "strip",
|
||||
"DMX Device": "scroll",
|
||||
"Mirror": "mirror",
|
||||
"Focus Point": "focus",
|
||||
"Other": "misc",
|
||||
"Automated Fixture": "mover",
|
||||
"Color Mixing Automated Fixture": "cmymvr",
|
||||
"Color Mixing Rectangular Beam (obsolete rgb)": "rgb",
|
||||
"Color Mixing Rectangular Beam (obsolete rgba)": "rgba",
|
||||
"Color Mixing Rectangular Beam": "led7",
|
||||
"Color Mixing Striplight": "led7s",
|
||||
"Color Mixing Leko / ERS": "cmers",
|
||||
"Color Mixing Zoom ERS": "cmzers",
|
||||
"Color Mixing DMX Device": "cmscroll",
|
||||
"Network Device": "netnode"
|
||||
}
|
||||
|
||||
self.kind_var = tk.StringVar()
|
||||
self.kind_dropdown = ttk.Combobox(kind_frame, textvariable=self.kind_var,
|
||||
values=list(self.kind_options.keys()),
|
||||
state="readonly",
|
||||
font=("Arial", 10))
|
||||
self.kind_dropdown.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
||||
self.kind_dropdown.current(0) # Set default to first option
|
||||
|
||||
# Extract button
|
||||
extract_btn = tk.Button(self.root, text="Extract and Convert",
|
||||
command=self.extract_and_convert,
|
||||
font=("Arial", 12, "bold"),
|
||||
bg="#4CAF50", fg="white",
|
||||
padx=20, pady=10)
|
||||
extract_btn.pack(pady=20)
|
||||
|
||||
# Status label
|
||||
self.status_label = tk.Label(self.root, text="",
|
||||
font=("Arial", 9), fg="blue")
|
||||
self.status_label.pack(pady=5)
|
||||
|
||||
def browse_file(self):
|
||||
filename = filedialog.askopenfilename(
|
||||
title="Select LXXPLOT File",
|
||||
filetypes=[("LXXPLOT files", "*.lxxplot"), ("All files", "*.*")]
|
||||
)
|
||||
if filename:
|
||||
self.input_file = filename
|
||||
self.file_label.config(text=os.path.basename(filename), fg="black")
|
||||
self.status_label.config(text="File loaded successfully", fg="green")
|
||||
|
||||
def extract_and_convert(self):
|
||||
# Validate inputs
|
||||
if not self.input_file:
|
||||
messagebox.showerror("Error", "Please select an input LXXPLOT file")
|
||||
return
|
||||
|
||||
output_filename = self.output_entry.get().strip()
|
||||
if not output_filename:
|
||||
messagebox.showerror("Error", "Please enter an output file name")
|
||||
return
|
||||
|
||||
# Get the directory of the input file and create full output path
|
||||
input_dir = os.path.dirname(self.input_file)
|
||||
output_file = os.path.join(input_dir, output_filename)
|
||||
|
||||
try:
|
||||
# Parse the LXXPLOT file (XML format)
|
||||
tree = ET.parse(self.input_file)
|
||||
root = tree.getroot()
|
||||
|
||||
# Find the shape tag using the xpath: /layers/layer/shape
|
||||
shape_element = root.find("./layers/layer/shape")
|
||||
|
||||
if shape_element is None:
|
||||
messagebox.showerror("Error",
|
||||
"Path '/layers/layer/shape' not found in the LXXPLOT file")
|
||||
return
|
||||
|
||||
# Create the new XML structure: /key/kentry/custom/symbol/group/shape
|
||||
new_root = ET.Element("key")
|
||||
kentry = ET.SubElement(new_root, "kentry")
|
||||
|
||||
# Add name, kind, and fname as siblings of custom with user-provided values
|
||||
name = ET.SubElement(kentry, "name")
|
||||
name.text = self.name_entry.get().strip()
|
||||
|
||||
id_elem = ET.SubElement(kentry, "id")
|
||||
id_elem.text = self.id_entry.get().strip()
|
||||
|
||||
kind = ET.SubElement(kentry, "kind")
|
||||
# Get the value corresponding to the selected display name
|
||||
selected_display = self.kind_var.get()
|
||||
kind.text = self.kind_options.get(selected_display, "")
|
||||
|
||||
fname = ET.SubElement(kentry, "fname")
|
||||
fname.text = self.fname_entry.get().strip()
|
||||
|
||||
custom = ET.SubElement(kentry, "custom")
|
||||
|
||||
symbol = ET.SubElement(custom, "symbol")
|
||||
group = ET.SubElement(symbol, "group")
|
||||
shape = ET.SubElement(group, "shape")
|
||||
|
||||
# Copy the content from shape element to the new shape element
|
||||
shape.text = shape_element.text
|
||||
shape.attrib = shape_element.attrib
|
||||
|
||||
# Copy all child elements from original shape to new shape
|
||||
for child in shape_element:
|
||||
shape.append(child)
|
||||
|
||||
# Create and write the new LXKEY file
|
||||
new_tree = ET.ElementTree(new_root)
|
||||
ET.indent(new_tree, space=" ")
|
||||
new_tree.write(output_file, encoding="utf-8", xml_declaration=True)
|
||||
|
||||
self.status_label.config(
|
||||
text=f"Successfully converted and saved to {output_filename}",
|
||||
fg="green"
|
||||
)
|
||||
messagebox.showinfo("Success",
|
||||
f"Shape content extracted and written to /key/kentry/custom/symbol/group/shape\nSaved to: {output_file}")
|
||||
|
||||
except ET.ParseError as e:
|
||||
messagebox.showerror("Parse Error",
|
||||
f"Failed to parse XML file:\n{str(e)}")
|
||||
self.status_label.config(text="Parse error", fg="red")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"An error occurred:\n{str(e)}")
|
||||
self.status_label.config(text="Error occurred", fg="red")
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = tk.Tk()
|
||||
app = XMLExtractorApp(root)
|
||||
root.mainloop()
|
||||
Reference in New Issue
Block a user