This commit is contained in:
parent
60fea74ebf
commit
6a06f32176
73
x0_main.py
73
x0_main.py
|
@ -5,6 +5,7 @@ import sys
|
||||||
import locale
|
import locale
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
|
|
||||||
# (Función get_console_encoding y variable CONSOLE_ENCODING como antes)
|
# (Función get_console_encoding y variable CONSOLE_ENCODING como antes)
|
||||||
def get_console_encoding():
|
def get_console_encoding():
|
||||||
"""Obtiene la codificación preferida de la consola, con fallback."""
|
"""Obtiene la codificación preferida de la consola, con fallback."""
|
||||||
|
@ -14,9 +15,11 @@ def get_console_encoding():
|
||||||
# Fallback común en Windows si falla getpreferredencoding
|
# Fallback común en Windows si falla getpreferredencoding
|
||||||
return "cp1252" # O prueba con 'utf-8' si cp1252 da problemas
|
return "cp1252" # O prueba con 'utf-8' si cp1252 da problemas
|
||||||
|
|
||||||
|
|
||||||
CONSOLE_ENCODING = get_console_encoding()
|
CONSOLE_ENCODING = get_console_encoding()
|
||||||
# print(f"Detected console encoding: {CONSOLE_ENCODING}")
|
# print(f"Detected console encoding: {CONSOLE_ENCODING}")
|
||||||
|
|
||||||
|
|
||||||
# (Función run_script como antes, usando CONSOLE_ENCODING)
|
# (Función run_script como antes, usando CONSOLE_ENCODING)
|
||||||
def run_script(script_name, xml_arg):
|
def run_script(script_name, xml_arg):
|
||||||
"""Runs a given script with the specified XML file argument."""
|
"""Runs a given script with the specified XML file argument."""
|
||||||
|
@ -24,17 +27,21 @@ def run_script(script_name, xml_arg):
|
||||||
script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), script_name)
|
script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), script_name)
|
||||||
# Usar la ruta absoluta al ejecutable de Python actual
|
# Usar la ruta absoluta al ejecutable de Python actual
|
||||||
python_executable = sys.executable
|
python_executable = sys.executable
|
||||||
command = [python_executable, script_path, xml_arg] # Usar la ruta absoluta de python
|
command = [
|
||||||
|
python_executable,
|
||||||
|
script_path,
|
||||||
|
xml_arg,
|
||||||
|
] # Usar la ruta absoluta de python
|
||||||
print(f"\n--- Running {script_name} with argument: {xml_arg} ---")
|
print(f"\n--- Running {script_name} with argument: {xml_arg} ---")
|
||||||
try:
|
try:
|
||||||
# Ejecutar el proceso hijo
|
# Ejecutar el proceso hijo
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
command,
|
command,
|
||||||
check=True, # Lanza excepción si el script falla (return code != 0)
|
check=True, # Lanza excepción si el script falla (return code != 0)
|
||||||
capture_output=True,# Captura stdout y stderr
|
capture_output=True, # Captura stdout y stderr
|
||||||
text=True, # Decodifica stdout/stderr como texto
|
text=True, # Decodifica stdout/stderr como texto
|
||||||
encoding=CONSOLE_ENCODING, # Usa la codificación detectada
|
encoding=CONSOLE_ENCODING, # Usa la codificación detectada
|
||||||
errors='replace' # Reemplaza caracteres no decodificables
|
errors="replace", # Reemplaza caracteres no decodificables
|
||||||
)
|
)
|
||||||
|
|
||||||
# Imprimir stdout y stderr si no están vacíos
|
# Imprimir stdout y stderr si no están vacíos
|
||||||
|
@ -45,7 +52,9 @@ def run_script(script_name, xml_arg):
|
||||||
print(stdout_clean)
|
print(stdout_clean)
|
||||||
if stderr_clean:
|
if stderr_clean:
|
||||||
# Imprimir stderr claramente para errores del script hijo
|
# Imprimir stderr claramente para errores del script hijo
|
||||||
print(f"--- Stderr ({script_name}) ---", file=sys.stderr) # Imprimir en stderr
|
print(
|
||||||
|
f"--- Stderr ({script_name}) ---", file=sys.stderr
|
||||||
|
) # Imprimir en stderr
|
||||||
print(stderr_clean, file=sys.stderr)
|
print(stderr_clean, file=sys.stderr)
|
||||||
print("--------------------------", file=sys.stderr)
|
print("--------------------------", file=sys.stderr)
|
||||||
|
|
||||||
|
@ -54,11 +63,17 @@ def run_script(script_name, xml_arg):
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
# Error si el script python o el ejecutable no se encuentran
|
# Error si el script python o el ejecutable no se encuentran
|
||||||
print(f"Error: Script '{script_path}' or Python executable '{python_executable}' not found.", file=sys.stderr)
|
print(
|
||||||
|
f"Error: Script '{script_path}' or Python executable '{python_executable}' not found.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
# Error si el script hijo devuelve un código de error (ej., sys.exit(1))
|
# Error si el script hijo devuelve un código de error (ej., sys.exit(1))
|
||||||
print(f"Error running {script_name}: Script returned non-zero exit code {e.returncode}.", file=sys.stderr)
|
print(
|
||||||
|
f"Error running {script_name}: Script returned non-zero exit code {e.returncode}.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
# Decodificar e imprimir stdout/stderr del proceso fallido
|
# Decodificar e imprimir stdout/stderr del proceso fallido
|
||||||
stdout_decoded = e.stdout.strip() if e.stdout else ""
|
stdout_decoded = e.stdout.strip() if e.stdout else ""
|
||||||
|
@ -74,9 +89,13 @@ def run_script(script_name, xml_arg):
|
||||||
return False # Indicar fallo
|
return False # Indicar fallo
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Otros errores inesperados
|
# Otros errores inesperados
|
||||||
print(f"An unexpected error occurred while running {script_name}: {e}", file=sys.stderr)
|
print(
|
||||||
|
f"An unexpected error occurred while running {script_name}: {e}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
# Imprimir traceback para depuración
|
# Imprimir traceback para depuración
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc(file=sys.stderr)
|
traceback.print_exc(file=sys.stderr)
|
||||||
return False # Indicar fallo
|
return False # Indicar fallo
|
||||||
|
|
||||||
|
@ -95,8 +114,13 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
# Verificar si el directorio 'XML Project' existe
|
# Verificar si el directorio 'XML Project' existe
|
||||||
if not os.path.isdir(xml_project_dir):
|
if not os.path.isdir(xml_project_dir):
|
||||||
print(f"Error: El directorio '{xml_project_dir}' no existe o no es un directorio.", file=sys.stderr)
|
print(
|
||||||
print("Por favor, crea el directorio 'XML Project' en la misma carpeta que este script y coloca tus archivos XML dentro.")
|
f"Error: El directorio '{xml_project_dir}' no existe o no es un directorio.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"Por favor, crea el directorio 'XML Project' en la misma carpeta que este script y coloca tus archivos XML dentro."
|
||||||
|
)
|
||||||
sys.exit(1) # Salir con error
|
sys.exit(1) # Salir con error
|
||||||
|
|
||||||
# Buscar todos los archivos .xml recursivamente
|
# Buscar todos los archivos .xml recursivamente
|
||||||
|
@ -104,7 +128,9 @@ if __name__ == "__main__":
|
||||||
xml_files_found = glob.glob(search_pattern, recursive=True)
|
xml_files_found = glob.glob(search_pattern, recursive=True)
|
||||||
|
|
||||||
if not xml_files_found:
|
if not xml_files_found:
|
||||||
print(f"No se encontraron archivos XML en '{xml_project_dir}' o sus subdirectorios.")
|
print(
|
||||||
|
f"No se encontraron archivos XML en '{xml_project_dir}' o sus subdirectorios."
|
||||||
|
)
|
||||||
sys.exit(0) # Salir limpiamente si no hay archivos
|
sys.exit(0) # Salir limpiamente si no hay archivos
|
||||||
|
|
||||||
print(f"Se encontraron {len(xml_files_found)} archivos XML para procesar:")
|
print(f"Se encontraron {len(xml_files_found)} archivos XML para procesar:")
|
||||||
|
@ -134,18 +160,29 @@ if __name__ == "__main__":
|
||||||
xml_dir = os.path.dirname(absolute_xml_filepath)
|
xml_dir = os.path.dirname(absolute_xml_filepath)
|
||||||
parsing_dir = os.path.join(xml_dir, "parsing")
|
parsing_dir = os.path.join(xml_dir, "parsing")
|
||||||
expected_json_file = os.path.join(parsing_dir, f"{xml_base_name}.json")
|
expected_json_file = os.path.join(parsing_dir, f"{xml_base_name}.json")
|
||||||
expected_processed_json = os.path.join(parsing_dir, f"{xml_base_name}_processed.json")
|
expected_processed_json = os.path.join(
|
||||||
|
parsing_dir, f"{xml_base_name}_processed.json"
|
||||||
|
)
|
||||||
|
|
||||||
# Ejecutar los scripts en secuencia
|
# Ejecutar los scripts en secuencia
|
||||||
success = True
|
success = True
|
||||||
if not run_script(script1, absolute_xml_filepath):
|
if not run_script(script1, absolute_xml_filepath):
|
||||||
print(f"\nPipeline falló en el script '{script1}' para el archivo: {relative_path}", file=sys.stderr)
|
print(
|
||||||
|
f"\nPipeline falló en el script '{script1}' para el archivo: {relative_path}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
success = False
|
success = False
|
||||||
elif not run_script(script2, absolute_xml_filepath):
|
elif not run_script(script2, absolute_xml_filepath):
|
||||||
print(f"\nPipeline falló en el script '{script2}' para el archivo: {relative_path}", file=sys.stderr)
|
print(
|
||||||
|
f"\nPipeline falló en el script '{script2}' para el archivo: {relative_path}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
success = False
|
success = False
|
||||||
elif not run_script(script3, absolute_xml_filepath):
|
elif not run_script(script3, absolute_xml_filepath):
|
||||||
print(f"\nPipeline falló en el script '{script3}' para el archivo: {relative_path}", file=sys.stderr)
|
print(
|
||||||
|
f"\nPipeline falló en el script '{script3}' para el archivo: {relative_path}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
# Actualizar contadores y mostrar estado
|
# Actualizar contadores y mostrar estado
|
||||||
|
@ -154,12 +191,16 @@ if __name__ == "__main__":
|
||||||
processed_count += 1
|
processed_count += 1
|
||||||
else:
|
else:
|
||||||
failed_count += 1
|
failed_count += 1
|
||||||
print(f"--- Pipeline falló para: {relative_path} ---", file=sys.stderr) # Indicar fallo
|
print(
|
||||||
|
f"--- Pipeline falló para: {relative_path} ---", file=sys.stderr
|
||||||
|
) # Indicar fallo
|
||||||
|
|
||||||
# --- PARTE 3: RESUMEN FINAL ---
|
# --- PARTE 3: RESUMEN FINAL ---
|
||||||
print("\n--- Resumen Final del Procesamiento ---")
|
print("\n--- Resumen Final del Procesamiento ---")
|
||||||
print(f"Total de archivos XML encontrados: {len(xml_files_found)}")
|
print(f"Total de archivos XML encontrados: {len(xml_files_found)}")
|
||||||
print(f"Archivos procesados exitosamente por el pipeline completo: {processed_count}")
|
print(
|
||||||
|
f"Archivos procesados exitosamente por el pipeline completo: {processed_count}"
|
||||||
|
)
|
||||||
print(f"Archivos que fallaron en algún punto del pipeline: {failed_count}")
|
print(f"Archivos que fallaron en algún punto del pipeline: {failed_count}")
|
||||||
print("---------------------------------------")
|
print("---------------------------------------")
|
||||||
|
|
||||||
|
|
332
x1_to_json.py
332
x1_to_json.py
|
@ -24,6 +24,7 @@ except ImportError as e:
|
||||||
|
|
||||||
# --- NUEVAS FUNCIONES DE PARSEO para UDT y Tag Table ---
|
# --- NUEVAS FUNCIONES DE PARSEO para UDT y Tag Table ---
|
||||||
|
|
||||||
|
|
||||||
def parse_udt(udt_element):
|
def parse_udt(udt_element):
|
||||||
"""Parsea un elemento <SW.Types.PlcStruct> (UDT)."""
|
"""Parsea un elemento <SW.Types.PlcStruct> (UDT)."""
|
||||||
print(" -> Detectado: PlcStruct (UDT)")
|
print(" -> Detectado: PlcStruct (UDT)")
|
||||||
|
@ -43,49 +44,68 @@ def parse_udt(udt_element):
|
||||||
name_node = attr_list.xpath("./Name/text()")
|
name_node = attr_list.xpath("./Name/text()")
|
||||||
block_data["block_name"] = name_node[0].strip() if name_node else "UnknownUDT"
|
block_data["block_name"] = name_node[0].strip() if name_node else "UnknownUDT"
|
||||||
# Comentario del UDT
|
# Comentario del UDT
|
||||||
comment_node_list = udt_element.xpath("./ObjectList/MultilingualText[@CompositionName='Comment']")
|
comment_node_list = udt_element.xpath(
|
||||||
|
"./ObjectList/MultilingualText[@CompositionName='Comment']"
|
||||||
|
)
|
||||||
if comment_node_list:
|
if comment_node_list:
|
||||||
block_data["block_comment"] = get_multilingual_text(comment_node_list[0])
|
block_data["block_comment"] = get_multilingual_text(comment_node_list[0])
|
||||||
else: # Fallback
|
else: # Fallback
|
||||||
comment_attr_node = attr_list.xpath("../ObjectList/MultilingualText[@CompositionName='Comment']") # Buscar desde el padre
|
comment_attr_node = attr_list.xpath(
|
||||||
if comment_attr_node :
|
"../ObjectList/MultilingualText[@CompositionName='Comment']"
|
||||||
block_data["block_comment"] = get_multilingual_text(comment_attr_node[0])
|
) # Buscar desde el padre
|
||||||
|
if comment_attr_node:
|
||||||
|
block_data["block_comment"] = get_multilingual_text(
|
||||||
|
comment_attr_node[0]
|
||||||
|
)
|
||||||
|
|
||||||
# Extraer interfaz (miembros)
|
# Extraer interfaz (miembros)
|
||||||
# La interfaz de un UDT suele estar directamente en <Interface><Sections><Section Name="None">
|
# La interfaz de un UDT suele estar directamente en <Interface><Sections><Section Name="None">
|
||||||
interface_node_list = udt_element.xpath(
|
interface_node_list = udt_element.xpath(
|
||||||
"./AttributeList/Interface/iface:Sections/iface:Section[@Name='None']", namespaces=ns
|
"./AttributeList/Interface/iface:Sections/iface:Section[@Name='None']",
|
||||||
|
namespaces=ns,
|
||||||
)
|
)
|
||||||
if interface_node_list:
|
if interface_node_list:
|
||||||
section_node = interface_node_list[0]
|
section_node = interface_node_list[0]
|
||||||
members_in_section = section_node.xpath("./iface:Member", namespaces=ns)
|
members_in_section = section_node.xpath("./iface:Member", namespaces=ns)
|
||||||
if members_in_section:
|
if members_in_section:
|
||||||
# Usar la función existente para parsear miembros
|
# Usar la función existente para parsear miembros
|
||||||
block_data["interface"]["None"] = parse_interface_members(members_in_section)
|
block_data["interface"]["None"] = parse_interface_members(
|
||||||
|
members_in_section
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print(f"Advertencia: Sección 'None' encontrada en UDT '{block_data['block_name']}' pero sin miembros.")
|
print(
|
||||||
|
f"Advertencia: Sección 'None' encontrada en UDT '{block_data['block_name']}' pero sin miembros."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Intentar buscar interfaz directamente si no está en AttributeList (menos común)
|
# Intentar buscar interfaz directamente si no está en AttributeList (menos común)
|
||||||
interface_node_direct = udt_element.xpath(
|
interface_node_direct = udt_element.xpath(
|
||||||
".//iface:Interface/iface:Sections/iface:Section[@Name='None']", namespaces=ns
|
".//iface:Interface/iface:Sections/iface:Section[@Name='None']",
|
||||||
|
namespaces=ns,
|
||||||
)
|
)
|
||||||
if interface_node_direct:
|
if interface_node_direct:
|
||||||
section_node = interface_node_direct[0]
|
section_node = interface_node_direct[0]
|
||||||
members_in_section = section_node.xpath("./iface:Member", namespaces=ns)
|
members_in_section = section_node.xpath("./iface:Member", namespaces=ns)
|
||||||
if members_in_section:
|
if members_in_section:
|
||||||
block_data["interface"]["None"] = parse_interface_members(members_in_section)
|
block_data["interface"]["None"] = parse_interface_members(
|
||||||
|
members_in_section
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print(f"Advertencia: Sección 'None' encontrada directamente en UDT '{block_data['block_name']}' pero sin miembros.")
|
print(
|
||||||
|
f"Advertencia: Sección 'None' encontrada directamente en UDT '{block_data['block_name']}' pero sin miembros."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print(f"Advertencia: No se encontró la sección 'None' de la interfaz para UDT '{block_data['block_name']}'.")
|
print(
|
||||||
|
f"Advertencia: No se encontró la sección 'None' de la interfaz para UDT '{block_data['block_name']}'."
|
||||||
|
)
|
||||||
|
|
||||||
if not block_data["interface"]:
|
if not block_data["interface"]:
|
||||||
print(f"Advertencia: No se pudo extraer la interfaz del UDT '{block_data['block_name']}'.")
|
print(
|
||||||
|
f"Advertencia: No se pudo extraer la interfaz del UDT '{block_data['block_name']}'."
|
||||||
|
)
|
||||||
|
|
||||||
return block_data
|
return block_data
|
||||||
|
|
||||||
|
|
||||||
def parse_tag_table(tag_table_element):
|
def parse_tag_table(tag_table_element):
|
||||||
"""Parsea un elemento <SW.Tags.PlcTagTable>."""
|
"""Parsea un elemento <SW.Tags.PlcTagTable>."""
|
||||||
print(" -> Detectado: PlcTagTable")
|
print(" -> Detectado: PlcTagTable")
|
||||||
|
@ -102,7 +122,9 @@ def parse_tag_table(tag_table_element):
|
||||||
attribute_list_node = tag_table_element.xpath("./AttributeList")
|
attribute_list_node = tag_table_element.xpath("./AttributeList")
|
||||||
if attribute_list_node:
|
if attribute_list_node:
|
||||||
name_node = attribute_list_node[0].xpath("./Name/text()")
|
name_node = attribute_list_node[0].xpath("./Name/text()")
|
||||||
table_data["block_name"] = name_node[0].strip() if name_node else "UnknownTagTable"
|
table_data["block_name"] = (
|
||||||
|
name_node[0].strip() if name_node else "UnknownTagTable"
|
||||||
|
)
|
||||||
|
|
||||||
# Extraer tags
|
# Extraer tags
|
||||||
tag_elements = tag_table_element.xpath("./ObjectList/SW.Tags.PlcTag")
|
tag_elements = tag_table_element.xpath("./ObjectList/SW.Tags.PlcTag")
|
||||||
|
@ -112,7 +134,7 @@ def parse_tag_table(tag_table_element):
|
||||||
"name": "UnknownTag",
|
"name": "UnknownTag",
|
||||||
"datatype": "Unknown",
|
"datatype": "Unknown",
|
||||||
"address": None,
|
"address": None,
|
||||||
"comment": ""
|
"comment": "",
|
||||||
}
|
}
|
||||||
tag_attr_list = tag_elem.xpath("./AttributeList")
|
tag_attr_list = tag_elem.xpath("./AttributeList")
|
||||||
if tag_attr_list:
|
if tag_attr_list:
|
||||||
|
@ -125,7 +147,9 @@ def parse_tag_table(tag_table_element):
|
||||||
tag_info["address"] = addr_node[0].strip() if addr_node else None
|
tag_info["address"] = addr_node[0].strip() if addr_node else None
|
||||||
|
|
||||||
# Extraer comentario del tag
|
# Extraer comentario del tag
|
||||||
comment_node_list = tag_elem.xpath("./ObjectList/MultilingualText[@CompositionName='Comment']")
|
comment_node_list = tag_elem.xpath(
|
||||||
|
"./ObjectList/MultilingualText[@CompositionName='Comment']"
|
||||||
|
)
|
||||||
if comment_node_list:
|
if comment_node_list:
|
||||||
tag_info["comment"] = get_multilingual_text(comment_node_list[0])
|
tag_info["comment"] = get_multilingual_text(comment_node_list[0])
|
||||||
|
|
||||||
|
@ -133,6 +157,7 @@ def parse_tag_table(tag_table_element):
|
||||||
|
|
||||||
return table_data
|
return table_data
|
||||||
|
|
||||||
|
|
||||||
# --- Cargador Dinámico de Parsers (sin cambios) ---
|
# --- Cargador Dinámico de Parsers (sin cambios) ---
|
||||||
def load_parsers(parsers_dir="parsers"):
|
def load_parsers(parsers_dir="parsers"):
|
||||||
"""
|
"""
|
||||||
|
@ -159,7 +184,9 @@ def load_parsers(parsers_dir="parsers"):
|
||||||
and filename not in ["__init__.py", "parser_utils.py"]
|
and filename not in ["__init__.py", "parser_utils.py"]
|
||||||
):
|
):
|
||||||
module_name_rel = filename[:-3] # Nombre sin .py (e.g., parse_lad_fbd)
|
module_name_rel = filename[:-3] # Nombre sin .py (e.g., parse_lad_fbd)
|
||||||
full_module_name = f"{parsers_package}.{module_name_rel}" # e.g., parsers.parse_lad_fbd
|
full_module_name = (
|
||||||
|
f"{parsers_package}.{module_name_rel}" # e.g., parsers.parse_lad_fbd
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
# Importar el módulo dinámicamente
|
# Importar el módulo dinámicamente
|
||||||
module = importlib.import_module(full_module_name)
|
module = importlib.import_module(full_module_name)
|
||||||
|
@ -213,6 +240,7 @@ def load_parsers(parsers_dir="parsers"):
|
||||||
print(f"Lenguajes soportados: {list(parser_map.keys())}")
|
print(f"Lenguajes soportados: {list(parser_map.keys())}")
|
||||||
return parser_map
|
return parser_map
|
||||||
|
|
||||||
|
|
||||||
# --- Función Principal de Conversión (MODIFICADA) ---
|
# --- Función Principal de Conversión (MODIFICADA) ---
|
||||||
def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
||||||
"""Convierte XML a JSON, detectando tipo de bloque (FC/FB/OB/DB/UDT/TagTable)."""
|
"""Convierte XML a JSON, detectando tipo de bloque (FC/FB/OB/DB/UDT/TagTable)."""
|
||||||
|
@ -223,7 +251,9 @@ def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print("Paso 1: Parseando archivo XML...")
|
print("Paso 1: Parseando archivo XML...")
|
||||||
parser = etree.XMLParser(remove_blank_text=True, recover=True) # recover=True puede ayudar
|
parser = etree.XMLParser(
|
||||||
|
remove_blank_text=True, recover=True
|
||||||
|
) # recover=True puede ayudar
|
||||||
tree = etree.parse(xml_filepath, parser)
|
tree = etree.parse(xml_filepath, parser)
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
print("Paso 1: Parseo XML completado.")
|
print("Paso 1: Parseo XML completado.")
|
||||||
|
@ -240,7 +270,9 @@ def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
||||||
|
|
||||||
# Buscar Tag Table si no es UDT
|
# Buscar Tag Table si no es UDT
|
||||||
if result is None:
|
if result is None:
|
||||||
tag_table_element = root.find(".//SW.Tags.PlcTagTable", namespaces=root.nsmap)
|
tag_table_element = root.find(
|
||||||
|
".//SW.Tags.PlcTagTable", namespaces=root.nsmap
|
||||||
|
)
|
||||||
if tag_table_element is not None:
|
if tag_table_element is not None:
|
||||||
result = parse_tag_table(tag_table_element)
|
result = parse_tag_table(tag_table_element)
|
||||||
|
|
||||||
|
@ -258,13 +290,21 @@ def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
||||||
if block_list:
|
if block_list:
|
||||||
the_block = block_list[0]
|
the_block = block_list[0]
|
||||||
block_tag_name = etree.QName(the_block.tag).localname
|
block_tag_name = etree.QName(the_block.tag).localname
|
||||||
if block_tag_name == "SW.Blocks.FC": block_type_found = "FC"
|
if block_tag_name == "SW.Blocks.FC":
|
||||||
elif block_tag_name == "SW.Blocks.FB": block_type_found = "FB"
|
block_type_found = "FC"
|
||||||
elif block_tag_name == "SW.Blocks.GlobalDB": block_type_found = "GlobalDB"
|
elif block_tag_name == "SW.Blocks.FB":
|
||||||
elif block_tag_name == "SW.Blocks.OB": block_type_found = "OB"
|
block_type_found = "FB"
|
||||||
print(f"Paso 2b: Bloque {block_tag_name} (Tipo: {block_type_found}) encontrado (ID={the_block.get('ID')}).")
|
elif block_tag_name == "SW.Blocks.GlobalDB":
|
||||||
|
block_type_found = "GlobalDB"
|
||||||
|
elif block_tag_name == "SW.Blocks.OB":
|
||||||
|
block_type_found = "OB"
|
||||||
|
print(
|
||||||
|
f"Paso 2b: Bloque {block_tag_name} (Tipo: {block_type_found}) encontrado (ID={the_block.get('ID')})."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print("Error Crítico: No se encontró el elemento raíz del bloque (<SW.Blocks.FC/FB/GlobalDB/OB>) ni UDT ni Tag Table.")
|
print(
|
||||||
|
"Error Crítico: No se encontró el elemento raíz del bloque (<SW.Blocks.FC/FB/GlobalDB/OB>) ni UDT ni Tag Table."
|
||||||
|
)
|
||||||
return False # Fallo si no se encuentra ningún objeto principal
|
return False # Fallo si no se encuentra ningún objeto principal
|
||||||
|
|
||||||
# --- Si es FC/FB/OB/DB, continuar con el parseo original ---
|
# --- Si es FC/FB/OB/DB, continuar con el parseo original ---
|
||||||
|
@ -272,28 +312,51 @@ def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
||||||
print("Paso 3: Extrayendo atributos del bloque...")
|
print("Paso 3: Extrayendo atributos del bloque...")
|
||||||
# (Extracción de atributos Name, Number, Language como antes...)
|
# (Extracción de atributos Name, Number, Language como antes...)
|
||||||
attribute_list_node = the_block.xpath("./AttributeList")
|
attribute_list_node = the_block.xpath("./AttributeList")
|
||||||
block_name_val, block_number_val, block_lang_val = "Unknown", None, "Unknown"
|
block_name_val, block_number_val, block_lang_val = (
|
||||||
|
"Unknown",
|
||||||
|
None,
|
||||||
|
"Unknown",
|
||||||
|
)
|
||||||
if attribute_list_node:
|
if attribute_list_node:
|
||||||
attr_list = attribute_list_node[0]
|
attr_list = attribute_list_node[0]
|
||||||
name_node = attr_list.xpath("./Name/text()")
|
name_node = attr_list.xpath("./Name/text()")
|
||||||
block_name_val = name_node[0].strip() if name_node else block_name_val
|
block_name_val = (
|
||||||
|
name_node[0].strip() if name_node else block_name_val
|
||||||
|
)
|
||||||
num_node = attr_list.xpath("./Number/text()")
|
num_node = attr_list.xpath("./Number/text()")
|
||||||
try: block_number_val = int(num_node[0]) if num_node else None
|
try:
|
||||||
except (ValueError, TypeError): block_number_val = None
|
block_number_val = int(num_node[0]) if num_node else None
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
block_number_val = None
|
||||||
lang_node = attr_list.xpath("./ProgrammingLanguage/text()")
|
lang_node = attr_list.xpath("./ProgrammingLanguage/text()")
|
||||||
block_lang_val = (lang_node[0].strip() if lang_node else ("DB" if block_type_found == "GlobalDB" else "Unknown"))
|
block_lang_val = (
|
||||||
print(f"Paso 3: Atributos: Nombre='{block_name_val}', Número={block_number_val}, Lenguaje Bloque='{block_lang_val}'")
|
lang_node[0].strip()
|
||||||
|
if lang_node
|
||||||
|
else ("DB" if block_type_found == "GlobalDB" else "Unknown")
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"Paso 3: Atributos: Nombre='{block_name_val}', Número={block_number_val}, Lenguaje Bloque='{block_lang_val}'"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print(f"Advertencia: No se encontró AttributeList para el bloque {block_type_found}.")
|
print(
|
||||||
if block_type_found == "GlobalDB": block_lang_val = "DB"
|
f"Advertencia: No se encontró AttributeList para el bloque {block_type_found}."
|
||||||
|
)
|
||||||
|
if block_type_found == "GlobalDB":
|
||||||
|
block_lang_val = "DB"
|
||||||
|
|
||||||
# (Extracción de comentario como antes...)
|
# (Extracción de comentario como antes...)
|
||||||
block_comment_val = ""
|
block_comment_val = ""
|
||||||
comment_node_list = the_block.xpath("./ObjectList/MultilingualText[@CompositionName='Comment']")
|
comment_node_list = the_block.xpath(
|
||||||
if comment_node_list: block_comment_val = get_multilingual_text(comment_node_list[0])
|
"./ObjectList/MultilingualText[@CompositionName='Comment']"
|
||||||
|
)
|
||||||
|
if comment_node_list:
|
||||||
|
block_comment_val = get_multilingual_text(comment_node_list[0])
|
||||||
else: # Fallback
|
else: # Fallback
|
||||||
comment_attr_node = the_block.xpath("./AttributeList/Comment") # Buscar desde AttributeList
|
comment_attr_node = the_block.xpath(
|
||||||
if comment_attr_node : block_comment_val = get_multilingual_text(comment_attr_node[0])
|
"./AttributeList/Comment"
|
||||||
|
) # Buscar desde AttributeList
|
||||||
|
if comment_attr_node:
|
||||||
|
block_comment_val = get_multilingual_text(comment_attr_node[0])
|
||||||
|
|
||||||
print(f"Paso 3b: Comentario bloque: '{block_comment_val[:50]}...'")
|
print(f"Paso 3b: Comentario bloque: '{block_comment_val[:50]}...'")
|
||||||
|
|
||||||
|
@ -310,29 +373,59 @@ def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
||||||
|
|
||||||
# (Extracción de interfaz como antes...)
|
# (Extracción de interfaz como antes...)
|
||||||
print("Paso 4: Extrayendo la interfaz del bloque...")
|
print("Paso 4: Extrayendo la interfaz del bloque...")
|
||||||
interface_node_list = attribute_list_node[0].xpath("./Interface") if attribute_list_node else []
|
interface_node_list = (
|
||||||
|
attribute_list_node[0].xpath("./Interface")
|
||||||
|
if attribute_list_node
|
||||||
|
else []
|
||||||
|
)
|
||||||
if interface_node_list:
|
if interface_node_list:
|
||||||
interface_node = interface_node_list[0]
|
interface_node = interface_node_list[0]
|
||||||
all_sections = interface_node.xpath(".//iface:Section", namespaces=ns)
|
all_sections = interface_node.xpath(
|
||||||
|
".//iface:Section", namespaces=ns
|
||||||
|
)
|
||||||
if all_sections:
|
if all_sections:
|
||||||
processed_sections = set()
|
processed_sections = set()
|
||||||
for section in all_sections:
|
for section in all_sections:
|
||||||
section_name = section.get("Name")
|
section_name = section.get("Name")
|
||||||
if not section_name or section_name in processed_sections: continue
|
if not section_name or section_name in processed_sections:
|
||||||
members_in_section = section.xpath("./iface:Member", namespaces=ns)
|
continue
|
||||||
|
members_in_section = section.xpath(
|
||||||
|
"./iface:Member", namespaces=ns
|
||||||
|
)
|
||||||
if members_in_section:
|
if members_in_section:
|
||||||
result["interface"][section_name] = parse_interface_members(members_in_section)
|
result["interface"][section_name] = (
|
||||||
|
parse_interface_members(members_in_section)
|
||||||
|
)
|
||||||
processed_sections.add(section_name)
|
processed_sections.add(section_name)
|
||||||
else: print("Advertencia: Nodo Interface no contiene secciones <iface:Section>.")
|
else:
|
||||||
if not result["interface"]: print("Advertencia: Interface encontrada pero sin secciones procesables.")
|
print(
|
||||||
|
"Advertencia: Nodo Interface no contiene secciones <iface:Section>."
|
||||||
|
)
|
||||||
|
if not result["interface"]:
|
||||||
|
print(
|
||||||
|
"Advertencia: Interface encontrada pero sin secciones procesables."
|
||||||
|
)
|
||||||
elif block_type_found == "GlobalDB":
|
elif block_type_found == "GlobalDB":
|
||||||
static_members = the_block.xpath(".//iface:Section[@Name='Static']/iface:Member", namespaces=ns)
|
static_members = the_block.xpath(
|
||||||
|
".//iface:Section[@Name='Static']/iface:Member", namespaces=ns
|
||||||
|
)
|
||||||
if static_members:
|
if static_members:
|
||||||
print("Paso 4: Encontrada sección Static para GlobalDB (sin nodo Interface).")
|
print(
|
||||||
result["interface"]["Static"] = parse_interface_members(static_members)
|
"Paso 4: Encontrada sección Static para GlobalDB (sin nodo Interface)."
|
||||||
else: print("Advertencia: No se encontró sección 'Static' para GlobalDB.")
|
)
|
||||||
else: print(f"Advertencia: No se encontró <Interface> para bloque {block_type_found}.")
|
result["interface"]["Static"] = parse_interface_members(
|
||||||
if not result["interface"]: print("Advertencia: No se pudo extraer información de la interfaz.")
|
static_members
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
"Advertencia: No se encontró sección 'Static' para GlobalDB."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"Advertencia: No se encontró <Interface> para bloque {block_type_found}."
|
||||||
|
)
|
||||||
|
if not result["interface"]:
|
||||||
|
print("Advertencia: No se pudo extraer información de la interfaz.")
|
||||||
|
|
||||||
# (Procesamiento de redes como antes, SOLO si NO es GlobalDB)
|
# (Procesamiento de redes como antes, SOLO si NO es GlobalDB)
|
||||||
if block_type_found != "GlobalDB":
|
if block_type_found != "GlobalDB":
|
||||||
|
@ -341,78 +434,143 @@ def convert_xml_to_json(xml_filepath, json_filepath, parser_map):
|
||||||
result["networks"] = []
|
result["networks"] = []
|
||||||
object_list_node = the_block.xpath("./ObjectList")
|
object_list_node = the_block.xpath("./ObjectList")
|
||||||
if object_list_node:
|
if object_list_node:
|
||||||
compile_units = object_list_node[0].xpath("./SW.Blocks.CompileUnit")
|
compile_units = object_list_node[0].xpath(
|
||||||
print(f"Paso 5: Se encontraron {len(compile_units)} elementos SW.Blocks.CompileUnit.")
|
"./SW.Blocks.CompileUnit"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"Paso 5: Se encontraron {len(compile_units)} elementos SW.Blocks.CompileUnit."
|
||||||
|
)
|
||||||
|
|
||||||
# Bucle de parseo de redes (igual que antes)
|
# Bucle de parseo de redes (igual que antes)
|
||||||
for network_elem in compile_units:
|
for network_elem in compile_units:
|
||||||
networks_processed_count += 1
|
networks_processed_count += 1
|
||||||
network_id = network_elem.get("ID")
|
network_id = network_elem.get("ID")
|
||||||
if not network_id: continue
|
if not network_id:
|
||||||
|
continue
|
||||||
network_lang = "LAD"
|
network_lang = "LAD"
|
||||||
net_attr_list = network_elem.xpath("./AttributeList")
|
net_attr_list = network_elem.xpath("./AttributeList")
|
||||||
if net_attr_list:
|
if net_attr_list:
|
||||||
lang_node = net_attr_list[0].xpath("./ProgrammingLanguage/text()")
|
lang_node = net_attr_list[0].xpath(
|
||||||
if lang_node: network_lang = lang_node[0].strip()
|
"./ProgrammingLanguage/text()"
|
||||||
print(f" - Procesando Red ID={network_id}, Lenguaje Red={network_lang}")
|
)
|
||||||
|
if lang_node:
|
||||||
|
network_lang = lang_node[0].strip()
|
||||||
|
print(
|
||||||
|
f" - Procesando Red ID={network_id}, Lenguaje Red={network_lang}"
|
||||||
|
)
|
||||||
parser_func = parser_map.get(network_lang.upper())
|
parser_func = parser_map.get(network_lang.upper())
|
||||||
parsed_network_data = None
|
parsed_network_data = None
|
||||||
if parser_func:
|
if parser_func:
|
||||||
try:
|
try:
|
||||||
parsed_network_data = parser_func(network_elem)
|
parsed_network_data = parser_func(network_elem)
|
||||||
except Exception as e_parse:
|
except Exception as e_parse:
|
||||||
print(f" ERROR durante el parseo de Red {network_id} ({network_lang}): {e_parse}")
|
print(
|
||||||
|
f" ERROR durante el parseo de Red {network_id} ({network_lang}): {e_parse}"
|
||||||
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
parsed_network_data = {"id": network_id, "language": network_lang, "logic": [], "error": f"Parser failed: {e_parse}"}
|
parsed_network_data = {
|
||||||
|
"id": network_id,
|
||||||
|
"language": network_lang,
|
||||||
|
"logic": [],
|
||||||
|
"error": f"Parser failed: {e_parse}",
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
print(f" Advertencia: Lenguaje de red '{network_lang}' no soportado.")
|
print(
|
||||||
parsed_network_data = {"id": network_id, "language": network_lang, "logic": [], "error": f"Unsupported language: {network_lang}"}
|
f" Advertencia: Lenguaje de red '{network_lang}' no soportado."
|
||||||
|
)
|
||||||
|
parsed_network_data = {
|
||||||
|
"id": network_id,
|
||||||
|
"language": network_lang,
|
||||||
|
"logic": [],
|
||||||
|
"error": f"Unsupported language: {network_lang}",
|
||||||
|
}
|
||||||
|
|
||||||
if parsed_network_data:
|
if parsed_network_data:
|
||||||
title_element = network_elem.xpath(".//iface:MultilingualText[@CompositionName='Title']",namespaces=ns)
|
title_element = network_elem.xpath(
|
||||||
parsed_network_data["title"] = (get_multilingual_text(title_element[0]) if title_element else f"Network {network_id}")
|
".//iface:MultilingualText[@CompositionName='Title']",
|
||||||
comment_elem_net = network_elem.xpath("./ObjectList/MultilingualText[@CompositionName='Comment']", namespaces=ns)
|
namespaces=ns,
|
||||||
if not comment_elem_net: comment_elem_net = network_elem.xpath(".//MultilingualText[@CompositionName='Comment']", namespaces=ns) # Fallback
|
)
|
||||||
parsed_network_data["comment"] = (get_multilingual_text(comment_elem_net[0]) if comment_elem_net else "")
|
parsed_network_data["title"] = (
|
||||||
|
get_multilingual_text(title_element[0])
|
||||||
|
if title_element
|
||||||
|
else f"Network {network_id}"
|
||||||
|
)
|
||||||
|
comment_elem_net = network_elem.xpath(
|
||||||
|
"./ObjectList/MultilingualText[@CompositionName='Comment']",
|
||||||
|
namespaces=ns,
|
||||||
|
)
|
||||||
|
if not comment_elem_net:
|
||||||
|
comment_elem_net = network_elem.xpath(
|
||||||
|
".//MultilingualText[@CompositionName='Comment']",
|
||||||
|
namespaces=ns,
|
||||||
|
) # Fallback
|
||||||
|
parsed_network_data["comment"] = (
|
||||||
|
get_multilingual_text(comment_elem_net[0])
|
||||||
|
if comment_elem_net
|
||||||
|
else ""
|
||||||
|
)
|
||||||
result["networks"].append(parsed_network_data)
|
result["networks"].append(parsed_network_data)
|
||||||
|
|
||||||
if networks_processed_count == 0: print(f"Advertencia: ObjectList para {block_type_found} sin SW.Blocks.CompileUnit.")
|
if networks_processed_count == 0:
|
||||||
else: print(f"Advertencia: No se encontró ObjectList para el bloque {block_type_found}.")
|
print(
|
||||||
|
f"Advertencia: ObjectList para {block_type_found} sin SW.Blocks.CompileUnit."
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"Advertencia: No se encontró ObjectList para el bloque {block_type_found}."
|
||||||
|
)
|
||||||
else: # Es GlobalDB
|
else: # Es GlobalDB
|
||||||
print("Paso 5: Saltando procesamiento de redes para GlobalDB.")
|
print("Paso 5: Saltando procesamiento de redes para GlobalDB.")
|
||||||
|
|
||||||
|
|
||||||
# --- Escritura del JSON (si se encontró un objeto) ---
|
# --- Escritura del JSON (si se encontró un objeto) ---
|
||||||
if result:
|
if result:
|
||||||
print("Paso 6: Escribiendo el resultado en el archivo JSON...")
|
print("Paso 6: Escribiendo el resultado en el archivo JSON...")
|
||||||
# Validaciones finales
|
# Validaciones finales
|
||||||
if result.get("block_type") not in ["PlcUDT", "PlcTagTable"] and not result["interface"]:
|
if (
|
||||||
|
result.get("block_type") not in ["PlcUDT", "PlcTagTable"]
|
||||||
|
and not result["interface"]
|
||||||
|
):
|
||||||
print("ADVERTENCIA FINAL: 'interface' está vacía en el JSON.")
|
print("ADVERTENCIA FINAL: 'interface' está vacía en el JSON.")
|
||||||
if result.get("block_type") not in ["PlcUDT", "PlcTagTable", "GlobalDB"] and not result["networks"]:
|
if (
|
||||||
|
result.get("block_type") not in ["PlcUDT", "PlcTagTable", "GlobalDB"]
|
||||||
|
and not result["networks"]
|
||||||
|
):
|
||||||
print("ADVERTENCIA FINAL: 'networks' está vacía en el JSON.")
|
print("ADVERTENCIA FINAL: 'networks' está vacía en el JSON.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(json_filepath, "w", encoding="utf-8") as f:
|
with open(json_filepath, "w", encoding="utf-8") as f:
|
||||||
json.dump(result, f, indent=4, ensure_ascii=False)
|
json.dump(result, f, indent=4, ensure_ascii=False)
|
||||||
print("Paso 6: Escritura JSON completada.")
|
print("Paso 6: Escritura JSON completada.")
|
||||||
print(f"Conversión finalizada. JSON guardado en: '{os.path.relpath(json_filepath)}'")
|
print(
|
||||||
|
f"Conversión finalizada. JSON guardado en: '{os.path.relpath(json_filepath)}'"
|
||||||
|
)
|
||||||
return True # Indicar éxito
|
return True # Indicar éxito
|
||||||
|
|
||||||
except IOError as e: print(f"Error Crítico: No se pudo escribir JSON en '{json_filepath}'. Error: {e}"); return False
|
except IOError as e:
|
||||||
except TypeError as e: print(f"Error Crítico: Problema al serializar a JSON. Error: {e}"); return False
|
print(
|
||||||
|
f"Error Crítico: No se pudo escribir JSON en '{json_filepath}'. Error: {e}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
except TypeError as e:
|
||||||
|
print(f"Error Crítico: Problema al serializar a JSON. Error: {e}")
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
print("Error Crítico: No se pudo determinar el tipo de objeto principal en el XML.")
|
print(
|
||||||
|
"Error Crítico: No se pudo determinar el tipo de objeto principal en el XML."
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
except etree.XMLSyntaxError as e:
|
except etree.XMLSyntaxError as e:
|
||||||
print(f"Error Crítico: Sintaxis XML inválida en '{xml_filepath}'. Detalles: {e}")
|
print(
|
||||||
|
f"Error Crítico: Sintaxis XML inválida en '{xml_filepath}'. Detalles: {e}"
|
||||||
|
)
|
||||||
return False # Indicar fallo
|
return False # Indicar fallo
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error Crítico: Error inesperado durante la conversión: {e}")
|
print(f"Error Crítico: Error inesperado durante la conversión: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False # Indicar fallo
|
return False # Indicar fallo
|
||||||
|
|
||||||
|
|
||||||
# --- Punto de Entrada Principal (__main__) ---
|
# --- Punto de Entrada Principal (__main__) ---
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
|
@ -426,15 +584,20 @@ if __name__ == "__main__":
|
||||||
xml_input_file = args.xml_filepath
|
xml_input_file = args.xml_filepath
|
||||||
|
|
||||||
if not os.path.exists(xml_input_file):
|
if not os.path.exists(xml_input_file):
|
||||||
print(f"Error Crítico (x1): Archivo XML no encontrado: '{xml_input_file}'", file=sys.stderr)
|
print(
|
||||||
|
f"Error Crítico (x1): Archivo XML no encontrado: '{xml_input_file}'",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# --- Cargar Parsers Dinámicamente ---
|
# --- Cargar Parsers Dinámicamente ---
|
||||||
loaded_parsers = load_parsers() # Carga parsers LAD/FBD/STL/SCL
|
loaded_parsers = load_parsers() # Carga parsers LAD/FBD/STL/SCL
|
||||||
if not loaded_parsers:
|
if not loaded_parsers:
|
||||||
# Continuar incluso sin parsers de red, ya que podríamos estar parseando UDT/TagTable
|
# Continuar incluso sin parsers de red, ya que podríamos estar parseando UDT/TagTable
|
||||||
print("Advertencia (x1): No se cargaron parsers de red. Se continuará para UDT/TagTable/DB.")
|
print(
|
||||||
#sys.exit(1) # Ya no salimos si no hay parsers de red
|
"Advertencia (x1): No se cargaron parsers de red. Se continuará para UDT/TagTable/DB."
|
||||||
|
)
|
||||||
|
# sys.exit(1) # Ya no salimos si no hay parsers de red
|
||||||
|
|
||||||
# Derivar nombre de salida JSON
|
# Derivar nombre de salida JSON
|
||||||
xml_filename_base = os.path.splitext(os.path.basename(xml_input_file))[0]
|
xml_filename_base = os.path.splitext(os.path.basename(xml_input_file))[0]
|
||||||
|
@ -443,7 +606,9 @@ if __name__ == "__main__":
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
json_output_file = os.path.join(output_dir, f"{xml_filename_base}.json")
|
json_output_file = os.path.join(output_dir, f"{xml_filename_base}.json")
|
||||||
|
|
||||||
print(f"(x1) Convirtiendo: '{os.path.relpath(xml_input_file)}' -> '{os.path.relpath(json_output_file)}'")
|
print(
|
||||||
|
f"(x1) Convirtiendo: '{os.path.relpath(xml_input_file)}' -> '{os.path.relpath(json_output_file)}'"
|
||||||
|
)
|
||||||
|
|
||||||
# Llamar a la función de conversión principal
|
# Llamar a la función de conversión principal
|
||||||
success = convert_xml_to_json(xml_input_file, json_output_file, loaded_parsers)
|
success = convert_xml_to_json(xml_input_file, json_output_file, loaded_parsers)
|
||||||
|
@ -452,5 +617,8 @@ if __name__ == "__main__":
|
||||||
if success:
|
if success:
|
||||||
sys.exit(0) # Éxito
|
sys.exit(0) # Éxito
|
||||||
else:
|
else:
|
||||||
print(f"\nError durante la conversión de '{os.path.relpath(xml_input_file)}'.", file=sys.stderr)
|
print(
|
||||||
|
f"\nError durante la conversión de '{os.path.relpath(xml_input_file)}'.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
sys.exit(1) # Fallo
|
sys.exit(1) # Fallo
|
194
x2_process.py
194
x2_process.py
|
@ -25,6 +25,7 @@ SIMPLIFIED_IF_COMMENT = "// Simplified IF condition by script"
|
||||||
# Global data dictionary
|
# Global data dictionary
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
|
||||||
# --- (process_group_ifs y load_processors SIN CAMBIOS) ---
|
# --- (process_group_ifs y load_processors SIN CAMBIOS) ---
|
||||||
def process_group_ifs(instruction, network_id, sympy_map, symbol_manager, data):
|
def process_group_ifs(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
"""
|
"""
|
||||||
|
@ -110,8 +111,14 @@ def process_group_ifs(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
"SCoil",
|
"SCoil",
|
||||||
"RCoil",
|
"RCoil",
|
||||||
"BLKMOV", # Added BLKMOV
|
"BLKMOV", # Added BLKMOV
|
||||||
"TON", "TOF", "TP", "Se", "Sd", # Added timers
|
"TON",
|
||||||
"CTU", "CTD", "CTUD", # Added counters
|
"TOF",
|
||||||
|
"TP",
|
||||||
|
"Se",
|
||||||
|
"Sd", # Added timers
|
||||||
|
"CTU",
|
||||||
|
"CTD",
|
||||||
|
"CTUD", # Added counters
|
||||||
]
|
]
|
||||||
|
|
||||||
for consumer_instr in network_logic:
|
for consumer_instr in network_logic:
|
||||||
|
@ -203,6 +210,7 @@ def process_group_ifs(instruction, network_id, sympy_map, symbol_manager, data):
|
||||||
|
|
||||||
return made_change
|
return made_change
|
||||||
|
|
||||||
|
|
||||||
def load_processors(processors_dir="processors"):
|
def load_processors(processors_dir="processors"):
|
||||||
"""
|
"""
|
||||||
Escanea el directorio, importa módulos, construye el mapa y una lista
|
Escanea el directorio, importa módulos, construye el mapa y una lista
|
||||||
|
@ -325,9 +333,15 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
print(f"Procesando bloque tipo: {block_type}")
|
print(f"Procesando bloque tipo: {block_type}")
|
||||||
|
|
||||||
# --- MODIFICADO: SALTAR PROCESAMIENTO PARA DB, UDT, TAG TABLE ---
|
# --- MODIFICADO: SALTAR PROCESAMIENTO PARA DB, UDT, TAG TABLE ---
|
||||||
if block_type in ["GlobalDB", "PlcUDT", "PlcTagTable"]: # <-- Comprobar tipos a saltar
|
if block_type in [
|
||||||
|
"GlobalDB",
|
||||||
|
"PlcUDT",
|
||||||
|
"PlcTagTable",
|
||||||
|
]: # <-- Comprobar tipos a saltar
|
||||||
print(f"INFO: El bloque es {block_type}. Saltando procesamiento lógico de x2.")
|
print(f"INFO: El bloque es {block_type}. Saltando procesamiento lógico de x2.")
|
||||||
print(f"Guardando JSON de {block_type} (sin cambios lógicos) en: {output_json_filepath}")
|
print(
|
||||||
|
f"Guardando JSON de {block_type} (sin cambios lógicos) en: {output_json_filepath}"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
with open(output_json_filepath, "w", encoding="utf-8") as f:
|
with open(output_json_filepath, "w", encoding="utf-8") as f:
|
||||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||||
|
@ -355,14 +369,26 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
current_access_map = {}
|
current_access_map = {}
|
||||||
for instr in network.get("logic", []):
|
for instr in network.get("logic", []):
|
||||||
for _, source in instr.get("inputs", {}).items():
|
for _, source in instr.get("inputs", {}).items():
|
||||||
sources_to_check = (source if isinstance(source, list) else ([source] if isinstance(source, dict) else []))
|
sources_to_check = (
|
||||||
|
source
|
||||||
|
if isinstance(source, list)
|
||||||
|
else ([source] if isinstance(source, dict) else [])
|
||||||
|
)
|
||||||
for src in sources_to_check:
|
for src in sources_to_check:
|
||||||
if (isinstance(src, dict) and src.get("uid") and src.get("type") in ["variable", "constant"]):
|
if (
|
||||||
|
isinstance(src, dict)
|
||||||
|
and src.get("uid")
|
||||||
|
and src.get("type") in ["variable", "constant"]
|
||||||
|
):
|
||||||
current_access_map[src["uid"]] = src
|
current_access_map[src["uid"]] = src
|
||||||
for _, dest_list in instr.get("outputs", {}).items():
|
for _, dest_list in instr.get("outputs", {}).items():
|
||||||
if isinstance(dest_list, list):
|
if isinstance(dest_list, list):
|
||||||
for dest in dest_list:
|
for dest in dest_list:
|
||||||
if (isinstance(dest, dict) and dest.get("uid") and dest.get("type") in ["variable", "constant"]):
|
if (
|
||||||
|
isinstance(dest, dict)
|
||||||
|
and dest.get("uid")
|
||||||
|
and dest.get("type") in ["variable", "constant"]
|
||||||
|
):
|
||||||
current_access_map[dest["uid"]] = dest
|
current_access_map[dest["uid"]] = dest
|
||||||
network_access_maps[net_id] = current_access_map
|
network_access_maps[net_id] = current_access_map
|
||||||
|
|
||||||
|
@ -391,7 +417,8 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
for network in data.get("networks", []):
|
for network in data.get("networks", []):
|
||||||
network_id = network["id"]
|
network_id = network["id"]
|
||||||
network_lang = network.get("language", "LAD")
|
network_lang = network.get("language", "LAD")
|
||||||
if network_lang == "STL": continue
|
if network_lang == "STL":
|
||||||
|
continue
|
||||||
|
|
||||||
access_map = network_access_maps.get(network_id, {})
|
access_map = network_access_maps.get(network_id, {})
|
||||||
network_logic = network.get("logic", [])
|
network_logic = network.get("logic", [])
|
||||||
|
@ -399,30 +426,51 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
instr_uid = instruction.get("instruction_uid")
|
instr_uid = instruction.get("instruction_uid")
|
||||||
instr_type_current = instruction.get("type", "Unknown")
|
instr_type_current = instruction.get("type", "Unknown")
|
||||||
|
|
||||||
if (instr_type_current.endswith(SCL_SUFFIX) or "_error" in instr_type_current or instruction.get("grouped", False) or
|
if (
|
||||||
instr_type_current in ["RAW_STL_CHUNK", "RAW_SCL_CHUNK", "UNSUPPORTED_LANG", "UNSUPPORTED_CONTENT", "PARSING_ERROR"]):
|
instr_type_current.endswith(SCL_SUFFIX)
|
||||||
|
or "_error" in instr_type_current
|
||||||
|
or instruction.get("grouped", False)
|
||||||
|
or instr_type_current
|
||||||
|
in [
|
||||||
|
"RAW_STL_CHUNK",
|
||||||
|
"RAW_SCL_CHUNK",
|
||||||
|
"UNSUPPORTED_LANG",
|
||||||
|
"UNSUPPORTED_CONTENT",
|
||||||
|
"PARSING_ERROR",
|
||||||
|
]
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
lookup_key = instr_type_current.lower()
|
lookup_key = instr_type_current.lower()
|
||||||
effective_type_name = lookup_key
|
effective_type_name = lookup_key
|
||||||
if instr_type_current == "Call":
|
if instr_type_current == "Call":
|
||||||
call_block_type = instruction.get("block_type", "").upper()
|
call_block_type = instruction.get("block_type", "").upper()
|
||||||
if call_block_type == "FC": effective_type_name = "call_fc"
|
if call_block_type == "FC":
|
||||||
elif call_block_type == "FB": effective_type_name = "call_fb"
|
effective_type_name = "call_fc"
|
||||||
|
elif call_block_type == "FB":
|
||||||
|
effective_type_name = "call_fb"
|
||||||
|
|
||||||
if effective_type_name == current_type_name:
|
if effective_type_name == current_type_name:
|
||||||
try:
|
try:
|
||||||
changed = func_to_call(instruction, network_id, sympy_map, symbol_manager, data)
|
changed = func_to_call(
|
||||||
|
instruction, network_id, sympy_map, symbol_manager, data
|
||||||
|
)
|
||||||
if changed:
|
if changed:
|
||||||
made_change_in_base_pass = True
|
made_change_in_base_pass = True
|
||||||
num_sympy_processed_this_pass += 1
|
num_sympy_processed_this_pass += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR(SymPy Base) al procesar {instr_type_current} UID {instr_uid}: {e}")
|
print(
|
||||||
|
f"ERROR(SymPy Base) al procesar {instr_type_current} UID {instr_uid}: {e}"
|
||||||
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
instruction["scl"] = f"// ERROR en SymPy procesador base: {e}"
|
instruction["scl"] = (
|
||||||
|
f"// ERROR en SymPy procesador base: {e}"
|
||||||
|
)
|
||||||
instruction["type"] = instr_type_current + "_error"
|
instruction["type"] = instr_type_current + "_error"
|
||||||
made_change_in_base_pass = True
|
made_change_in_base_pass = True
|
||||||
print(f" -> {num_sympy_processed_this_pass} instrucciones (no STL) procesadas con SymPy.")
|
print(
|
||||||
|
f" -> {num_sympy_processed_this_pass} instrucciones (no STL) procesadas con SymPy."
|
||||||
|
)
|
||||||
|
|
||||||
# FASE 2: Agrupación IF (Ignorando STL)
|
# FASE 2: Agrupación IF (Ignorando STL)
|
||||||
if made_change_in_base_pass or passes == 1:
|
if made_change_in_base_pass or passes == 1:
|
||||||
|
@ -431,30 +479,58 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
for network in data.get("networks", []):
|
for network in data.get("networks", []):
|
||||||
network_id = network["id"]
|
network_id = network["id"]
|
||||||
network_lang = network.get("language", "LAD")
|
network_lang = network.get("language", "LAD")
|
||||||
if network_lang == "STL": continue
|
if network_lang == "STL":
|
||||||
|
continue
|
||||||
network_logic = network.get("logic", [])
|
network_logic = network.get("logic", [])
|
||||||
uids_in_network = sorted([instr.get("instruction_uid", "Z") for instr in network_logic if instr.get("instruction_uid")])
|
uids_in_network = sorted(
|
||||||
|
[
|
||||||
|
instr.get("instruction_uid", "Z")
|
||||||
|
for instr in network_logic
|
||||||
|
if instr.get("instruction_uid")
|
||||||
|
]
|
||||||
|
)
|
||||||
for uid_to_process in uids_in_network:
|
for uid_to_process in uids_in_network:
|
||||||
instruction = next((instr for instr in network_logic if instr.get("instruction_uid") == uid_to_process), None)
|
instruction = next(
|
||||||
if not instruction: continue
|
(
|
||||||
if instruction.get("grouped") or "_error" in instruction.get("type", ""): continue
|
instr
|
||||||
|
for instr in network_logic
|
||||||
|
if instr.get("instruction_uid") == uid_to_process
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if not instruction:
|
||||||
|
continue
|
||||||
|
if instruction.get("grouped") or "_error" in instruction.get(
|
||||||
|
"type", ""
|
||||||
|
):
|
||||||
|
continue
|
||||||
if instruction.get("type", "").endswith(SCL_SUFFIX):
|
if instruction.get("type", "").endswith(SCL_SUFFIX):
|
||||||
try:
|
try:
|
||||||
group_changed = process_group_ifs(instruction, network_id, sympy_map, symbol_manager, data)
|
group_changed = process_group_ifs(
|
||||||
|
instruction, network_id, sympy_map, symbol_manager, data
|
||||||
|
)
|
||||||
if group_changed:
|
if group_changed:
|
||||||
made_change_in_group_pass = True
|
made_change_in_group_pass = True
|
||||||
num_grouped_this_pass += 1
|
num_grouped_this_pass += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR(GroupLoop) al intentar agrupar desde UID {instruction.get('instruction_uid')}: {e}")
|
print(
|
||||||
|
f"ERROR(GroupLoop) al intentar agrupar desde UID {instruction.get('instruction_uid')}: {e}"
|
||||||
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
print(f" -> {num_grouped_this_pass} agrupaciones realizadas (en redes no STL).")
|
print(
|
||||||
|
f" -> {num_grouped_this_pass} agrupaciones realizadas (en redes no STL)."
|
||||||
|
)
|
||||||
|
|
||||||
# Comprobar si se completó
|
# Comprobar si se completó
|
||||||
if not made_change_in_base_pass and not made_change_in_group_pass:
|
if not made_change_in_base_pass and not made_change_in_group_pass:
|
||||||
print(f"\n--- No se hicieron más cambios en el pase {passes}. Proceso iterativo completado. ---")
|
print(
|
||||||
|
f"\n--- No se hicieron más cambios en el pase {passes}. Proceso iterativo completado. ---"
|
||||||
|
)
|
||||||
processing_complete = True
|
processing_complete = True
|
||||||
else:
|
else:
|
||||||
print(f"--- Fin Pase {passes}: {num_sympy_processed_this_pass} proc SymPy, {num_grouped_this_pass} agrup. Continuando...")
|
print(
|
||||||
|
f"--- Fin Pase {passes}: {num_sympy_processed_this_pass} proc SymPy, {num_grouped_this_pass} agrup. Continuando..."
|
||||||
|
)
|
||||||
if passes == max_passes and not processing_complete:
|
if passes == max_passes and not processing_complete:
|
||||||
print(f"\n--- ADVERTENCIA: Límite de {max_passes} pases alcanzado...")
|
print(f"\n--- ADVERTENCIA: Límite de {max_passes} pases alcanzado...")
|
||||||
|
|
||||||
|
@ -464,23 +540,43 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
print(f"\n--- Verificación Final de Instrucciones No Procesadas ({block_type}) ---")
|
print(f"\n--- Verificación Final de Instrucciones No Procesadas ({block_type}) ---")
|
||||||
unprocessed_count = 0
|
unprocessed_count = 0
|
||||||
unprocessed_details = []
|
unprocessed_details = []
|
||||||
ignored_types = ["raw_scl_chunk", "unsupported_lang", "raw_stl_chunk", "unsupported_content", "parsing_error"]
|
ignored_types = [
|
||||||
|
"raw_scl_chunk",
|
||||||
|
"unsupported_lang",
|
||||||
|
"raw_stl_chunk",
|
||||||
|
"unsupported_content",
|
||||||
|
"parsing_error",
|
||||||
|
]
|
||||||
for network in data.get("networks", []):
|
for network in data.get("networks", []):
|
||||||
network_id = network.get("id", "Unknown ID")
|
network_id = network.get("id", "Unknown ID")
|
||||||
network_title = network.get("title", f"Network {network_id}")
|
network_title = network.get("title", f"Network {network_id}")
|
||||||
network_lang = network.get("language", "LAD")
|
network_lang = network.get("language", "LAD")
|
||||||
if network_lang == "STL": continue
|
if network_lang == "STL":
|
||||||
|
continue
|
||||||
for instruction in network.get("logic", []):
|
for instruction in network.get("logic", []):
|
||||||
instr_uid = instruction.get("instruction_uid", "Unknown UID")
|
instr_uid = instruction.get("instruction_uid", "Unknown UID")
|
||||||
instr_type = instruction.get("type", "Unknown Type")
|
instr_type = instruction.get("type", "Unknown Type")
|
||||||
is_grouped = instruction.get("grouped", False)
|
is_grouped = instruction.get("grouped", False)
|
||||||
if (not instr_type.endswith(SCL_SUFFIX) and "_error" not in instr_type and not is_grouped and instr_type.lower() not in ignored_types):
|
if (
|
||||||
|
not instr_type.endswith(SCL_SUFFIX)
|
||||||
|
and "_error" not in instr_type
|
||||||
|
and not is_grouped
|
||||||
|
and instr_type.lower() not in ignored_types
|
||||||
|
):
|
||||||
unprocessed_count += 1
|
unprocessed_count += 1
|
||||||
unprocessed_details.append(f" - Red '{network_title}' (ID: {network_id}, Lang: {network_lang}), Instrucción UID: {instr_uid}, Tipo: '{instr_type}'")
|
unprocessed_details.append(
|
||||||
|
f" - Red '{network_title}' (ID: {network_id}, Lang: {network_lang}), Instrucción UID: {instr_uid}, Tipo: '{instr_type}'"
|
||||||
|
)
|
||||||
if unprocessed_count > 0:
|
if unprocessed_count > 0:
|
||||||
print(f"ADVERTENCIA: Se encontraron {unprocessed_count} instrucciones (no STL) que parecen no haber sido procesadas:")
|
print(
|
||||||
for detail in unprocessed_details: print(detail)
|
f"ADVERTENCIA: Se encontraron {unprocessed_count} instrucciones (no STL) que parecen no haber sido procesadas:"
|
||||||
else: print("INFO: Todas las instrucciones relevantes (no STL) parecen haber sido procesadas o agrupadas.")
|
)
|
||||||
|
for detail in unprocessed_details:
|
||||||
|
print(detail)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
"INFO: Todas las instrucciones relevantes (no STL) parecen haber sido procesadas o agrupadas."
|
||||||
|
)
|
||||||
|
|
||||||
print(f"\nGuardando JSON procesado ({block_type}) en: {output_json_filepath}")
|
print(f"\nGuardando JSON procesado ({block_type}) en: {output_json_filepath}")
|
||||||
try:
|
try:
|
||||||
|
@ -489,19 +585,27 @@ def process_json_to_scl(json_filepath, output_json_filepath):
|
||||||
print("Guardado completado.")
|
print("Guardado completado.")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error Crítico al guardar JSON procesado: {e}");
|
print(f"Error Crítico al guardar JSON procesado: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
# --- Ejecución (MODIFICADO) ---
|
# --- Ejecución (MODIFICADO) ---
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Process simplified JSON to embed SCL logic. Expects original XML filepath as argument.")
|
parser = argparse.ArgumentParser(
|
||||||
parser.add_argument("source_xml_filepath", help="Path to the original source XML file (passed from x0_main.py).")
|
description="Process simplified JSON to embed SCL logic. Expects original XML filepath as argument."
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"source_xml_filepath",
|
||||||
|
help="Path to the original source XML file (passed from x0_main.py).",
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
source_xml_file = args.source_xml_filepath
|
source_xml_file = args.source_xml_filepath
|
||||||
|
|
||||||
if not os.path.exists(source_xml_file):
|
if not os.path.exists(source_xml_file):
|
||||||
print(f"Advertencia (x2): Archivo XML original no encontrado: '{source_xml_file}', pero se intentará encontrar el JSON correspondiente.")
|
print(
|
||||||
|
f"Advertencia (x2): Archivo XML original no encontrado: '{source_xml_file}', pero se intentará encontrar el JSON correspondiente."
|
||||||
|
)
|
||||||
|
|
||||||
xml_filename_base = os.path.splitext(os.path.basename(source_xml_file))[0]
|
xml_filename_base = os.path.splitext(os.path.basename(source_xml_file))[0]
|
||||||
base_dir = os.path.dirname(source_xml_file)
|
base_dir = os.path.dirname(source_xml_file)
|
||||||
|
@ -511,11 +615,17 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
os.makedirs(parsing_dir, exist_ok=True)
|
os.makedirs(parsing_dir, exist_ok=True)
|
||||||
|
|
||||||
print(f"(x2) Procesando: '{os.path.relpath(input_json_file)}' -> '{os.path.relpath(output_json_file)}'")
|
print(
|
||||||
|
f"(x2) Procesando: '{os.path.relpath(input_json_file)}' -> '{os.path.relpath(output_json_file)}'"
|
||||||
|
)
|
||||||
|
|
||||||
if not os.path.exists(input_json_file):
|
if not os.path.exists(input_json_file):
|
||||||
print(f"Error Fatal (x2): El archivo de entrada JSON no existe: '{input_json_file}'")
|
print(
|
||||||
print(f"Asegúrate de que 'x1_to_json.py' se ejecutó correctamente para '{os.path.relpath(source_xml_file)}'.")
|
f"Error Fatal (x2): El archivo de entrada JSON no existe: '{input_json_file}'"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"Asegúrate de que 'x1_to_json.py' se ejecutó correctamente para '{os.path.relpath(source_xml_file)}'."
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -525,6 +635,8 @@ if __name__ == "__main__":
|
||||||
else:
|
else:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error Crítico (x2) durante el procesamiento de '{input_json_file}': {e}")
|
print(
|
||||||
|
f"Error Crítico (x2) durante el procesamiento de '{input_json_file}': {e}"
|
||||||
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
|
@ -13,6 +13,7 @@ try:
|
||||||
from generators.generate_scl_code_block import generate_scl_for_code_block
|
from generators.generate_scl_code_block import generate_scl_for_code_block
|
||||||
from generators.generate_md_udt import generate_udt_markdown
|
from generators.generate_md_udt import generate_udt_markdown
|
||||||
from generators.generate_md_tag_table import generate_tag_table_markdown
|
from generators.generate_md_tag_table import generate_tag_table_markdown
|
||||||
|
|
||||||
# Importar format_variable_name (necesario para el nombre de archivo)
|
# Importar format_variable_name (necesario para el nombre de archivo)
|
||||||
from generators.generator_utils import format_variable_name
|
from generators.generator_utils import format_variable_name
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
|
@ -20,6 +21,7 @@ except ImportError as e:
|
||||||
print("Asegúrate de que el directorio 'generators' y sus archivos .py existen.")
|
print("Asegúrate de que el directorio 'generators' y sus archivos .py existen.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
# --- Función Principal de Generación (Despachador) ---
|
# --- Función Principal de Generación (Despachador) ---
|
||||||
def generate_scl_or_markdown(processed_json_filepath, output_directory):
|
def generate_scl_or_markdown(processed_json_filepath, output_directory):
|
||||||
"""
|
"""
|
||||||
|
@ -35,7 +37,9 @@ def generate_scl_or_markdown(processed_json_filepath, output_directory):
|
||||||
with open(processed_json_filepath, "r", encoding="utf-8") as f:
|
with open(processed_json_filepath, "r", encoding="utf-8") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error al cargar/parsear JSON: {e}"); traceback.print_exc(); return
|
print(f"Error al cargar/parsear JSON: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
return
|
||||||
|
|
||||||
block_name = data.get("block_name", "UnknownBlock")
|
block_name = data.get("block_name", "UnknownBlock")
|
||||||
block_type = data.get("block_type", "Unknown")
|
block_type = data.get("block_type", "Unknown")
|
||||||
|
@ -43,7 +47,9 @@ def generate_scl_or_markdown(processed_json_filepath, output_directory):
|
||||||
output_content = []
|
output_content = []
|
||||||
output_extension = ".scl" # Default
|
output_extension = ".scl" # Default
|
||||||
|
|
||||||
print(f"Generando salida para: {block_type} '{scl_block_name}' (Original: {block_name})")
|
print(
|
||||||
|
f"Generando salida para: {block_type} '{scl_block_name}' (Original: {block_name})"
|
||||||
|
)
|
||||||
|
|
||||||
# --- Selección del Generador y Extensión ---
|
# --- Selección del Generador y Extensión ---
|
||||||
generation_function = None
|
generation_function = None
|
||||||
|
@ -64,7 +70,9 @@ def generate_scl_or_markdown(processed_json_filepath, output_directory):
|
||||||
generation_function = generate_scl_for_code_block
|
generation_function = generate_scl_for_code_block
|
||||||
output_extension = ".scl"
|
output_extension = ".scl"
|
||||||
else: # Tipo desconocido
|
else: # Tipo desconocido
|
||||||
print(f"Error: Tipo de bloque desconocido '{block_type}'. No se generará archivo.")
|
print(
|
||||||
|
f"Error: Tipo de bloque desconocido '{block_type}'. No se generará archivo."
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# --- Llamar a la función generadora ---
|
# --- Llamar a la función generadora ---
|
||||||
|
@ -72,7 +80,9 @@ def generate_scl_or_markdown(processed_json_filepath, output_directory):
|
||||||
try:
|
try:
|
||||||
output_content = generation_function(data)
|
output_content = generation_function(data)
|
||||||
except Exception as gen_e:
|
except Exception as gen_e:
|
||||||
print(f"Error durante la generación de contenido para {block_type} '{scl_block_name}': {gen_e}")
|
print(
|
||||||
|
f"Error durante la generación de contenido para {block_type} '{scl_block_name}': {gen_e}"
|
||||||
|
)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return # No intentar escribir si la generación falla
|
return # No intentar escribir si la generación falla
|
||||||
|
|
||||||
|
@ -91,20 +101,35 @@ def generate_scl_or_markdown(processed_json_filepath, output_directory):
|
||||||
print(f"Error al escribir el archivo {output_extension.upper()}: {e}")
|
print(f"Error al escribir el archivo {output_extension.upper()}: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
# --- Ejecución ---
|
# --- Ejecución ---
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Generate final SCL or Markdown file.")
|
parser = argparse.ArgumentParser(description="Generate final SCL or Markdown file.")
|
||||||
parser.add_argument("source_xml_filepath", help="Path to the original source XML file.")
|
parser.add_argument(
|
||||||
args = parser.parse_args(); source_xml_file = args.source_xml_filepath
|
"source_xml_filepath", help="Path to the original source XML file."
|
||||||
if not os.path.exists(source_xml_file): print(f"Advertencia (x3): Archivo XML original no encontrado: '{source_xml_file}'.")
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
source_xml_file = args.source_xml_filepath
|
||||||
|
if not os.path.exists(source_xml_file):
|
||||||
|
print(
|
||||||
|
f"Advertencia (x3): Archivo XML original no encontrado: '{source_xml_file}'."
|
||||||
|
)
|
||||||
xml_filename_base = os.path.splitext(os.path.basename(source_xml_file))[0]
|
xml_filename_base = os.path.splitext(os.path.basename(source_xml_file))[0]
|
||||||
base_dir = os.path.dirname(source_xml_file)
|
base_dir = os.path.dirname(source_xml_file)
|
||||||
parsing_dir = os.path.join(base_dir, "parsing")
|
parsing_dir = os.path.join(base_dir, "parsing")
|
||||||
input_json_file = os.path.join(parsing_dir, f"{xml_filename_base}_processed.json")
|
input_json_file = os.path.join(parsing_dir, f"{xml_filename_base}_processed.json")
|
||||||
output_dir = base_dir
|
output_dir = base_dir
|
||||||
print(f"(x3) Generando SCL/MD desde: '{os.path.relpath(input_json_file)}' en directorio: '{os.path.relpath(output_dir)}'")
|
print(
|
||||||
|
f"(x3) Generando SCL/MD desde: '{os.path.relpath(input_json_file)}' en directorio: '{os.path.relpath(output_dir)}'"
|
||||||
|
)
|
||||||
if not os.path.exists(input_json_file):
|
if not os.path.exists(input_json_file):
|
||||||
print(f"Error Fatal (x3): JSON procesado no encontrado: '{input_json_file}'"); sys.exit(1)
|
print(f"Error Fatal (x3): JSON procesado no encontrado: '{input_json_file}'")
|
||||||
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
try: generate_scl_or_markdown(input_json_file, output_dir); sys.exit(0)
|
try:
|
||||||
except Exception as e: print(f"Error Crítico (x3): {e}"); traceback.print_exc(); sys.exit(1)
|
generate_scl_or_markdown(input_json_file, output_dir)
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error Crítico (x3): {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
|
|
Loading…
Reference in New Issue