- Reorganized project: codesys/, docs/codesys|redesign|integration|reference/, scripts/ - CODESYS project and exports in codesys/ - Documentation index in docs/README.md - Redesign and light naming configuration - Water boiler control and safety design Co-authored-by: Cursor <cursoragent@cursor.com>
138 lines
4.1 KiB
Python
Executable File
138 lines
4.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
CODESYS XML Export Parser
|
|
|
|
This script parses exported CODESYS XML files (.export or .xml) to extract
|
|
useful information for documentation.
|
|
|
|
Usage:
|
|
python3 parse-codesys-xml.py <export_file.export>
|
|
python3 parse-codesys-xml.py <export_file.xml>
|
|
"""
|
|
|
|
import sys
|
|
import xml.etree.ElementTree as ET
|
|
from pathlib import Path
|
|
from typing import Dict, List, Optional
|
|
|
|
|
|
def parse_codesys_export(file_path: str) -> Dict:
|
|
"""Parse a CODESYS XML export file."""
|
|
try:
|
|
tree = ET.parse(file_path)
|
|
root = tree.getroot()
|
|
return extract_project_info(root)
|
|
except ET.ParseError as e:
|
|
print(f"Error parsing XML: {e}")
|
|
return {}
|
|
except Exception as e:
|
|
print(f"Error reading file: {e}")
|
|
return {}
|
|
|
|
|
|
def extract_project_info(root: ET.Element) -> Dict:
|
|
"""Extract project information from XML root."""
|
|
info = {
|
|
'project_name': '',
|
|
'network_variables': [],
|
|
'programs': [],
|
|
'function_blocks': [],
|
|
'io_config': [],
|
|
'variables': []
|
|
}
|
|
|
|
# Try to find project name
|
|
project_elem = root.find('.//Project')
|
|
if project is not None:
|
|
info['project_name'] = project_elem.get('Name', 'Unknown')
|
|
|
|
# Extract network variables
|
|
# (Structure depends on CODESYS version and export format)
|
|
for nv in root.findall('.//NetworkVariable'):
|
|
nv_info = {
|
|
'name': nv.get('Name', ''),
|
|
'type': nv.get('Type', ''),
|
|
'direction': nv.get('Direction', ''),
|
|
'initial_value': nv.get('InitialValue', '')
|
|
}
|
|
info['network_variables'].append(nv_info)
|
|
|
|
# Extract programs/POUs
|
|
for pou in root.findall('.//POU'):
|
|
pou_info = {
|
|
'name': pou.get('Name', ''),
|
|
'type': pou.get('POUType', ''),
|
|
'language': pou.get('Language', '')
|
|
}
|
|
info['programs'].append(pou_info)
|
|
|
|
# Extract function blocks
|
|
for fb in root.findall('.//FunctionBlock'):
|
|
fb_info = {
|
|
'name': fb.get('Name', ''),
|
|
'type': fb.get('Type', '')
|
|
}
|
|
info['function_blocks'].append(fb_info)
|
|
|
|
return info
|
|
|
|
|
|
def print_summary(info: Dict):
|
|
"""Print a summary of extracted information."""
|
|
print("=" * 60)
|
|
print("CODESYS Project Summary")
|
|
print("=" * 60)
|
|
|
|
if info.get('project_name'):
|
|
print(f"\nProject Name: {info['project_name']}")
|
|
|
|
if info.get('network_variables'):
|
|
print(f"\nNetwork Variables ({len(info['network_variables'])}):")
|
|
for nv in info['network_variables']:
|
|
print(f" - {nv['name']} ({nv['type']}) [{nv.get('direction', 'N/A')}]")
|
|
|
|
if info.get('programs'):
|
|
print(f"\nPrograms/POUs ({len(info['programs'])}):")
|
|
for prog in info['programs']:
|
|
print(f" - {prog['name']} ({prog['type']}) [{prog.get('language', 'N/A')}]")
|
|
|
|
if info.get('function_blocks'):
|
|
print(f"\nFunction Blocks ({len(info['function_blocks'])}):")
|
|
for fb in info['function_blocks']:
|
|
print(f" - {fb['name']} ({fb.get('type', 'N/A')})")
|
|
|
|
print("\n" + "=" * 60)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python3 parse-codesys-xml.py <export_file.export|.xml>")
|
|
sys.exit(1)
|
|
|
|
file_path = sys.argv[1]
|
|
|
|
if not Path(file_path).exists():
|
|
print(f"Error: File not found: {file_path}")
|
|
sys.exit(1)
|
|
|
|
print(f"Parsing: {file_path}")
|
|
info = parse_codesys_export(file_path)
|
|
|
|
if info:
|
|
print_summary(info)
|
|
|
|
# Optionally save to JSON
|
|
if len(sys.argv) > 2 and sys.argv[2] == '--json':
|
|
import json
|
|
output_file = Path(file_path).stem + '_parsed.json'
|
|
with open(output_file, 'w') as f:
|
|
json.dump(info, f, indent=2)
|
|
print(f"\nParsed data saved to: {output_file}")
|
|
else:
|
|
print("No information extracted. The XML structure may be different.")
|
|
print("Try opening the file in a text editor to inspect its structure.")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|