Files
OIM-connector-Public/src/xml_parser.py
T

126 lines
6.4 KiB
Python

import lxml.etree as ET
from pathlib import Path
import click
from models.savefile import SaveFile
def write_xml_data(savefile: SaveFile) -> None:
filename = Path("output/CodeServerConnector.xml")
if not filename.parent.exists():
filename.parent.mkdir(parents=True, exist_ok=True)
root = _generate_xml_configuration()
for code in savefile.conceptCodes:
root = add_connection(root, code.name, code.attributes)
xml_str = ET.tostring(root, encoding="utf-8", xml_declaration=True, pretty_print=True).decode("utf-8-sig")
with open(filename, "w", encoding="utf-8-sig") as f:
f.write(xml_str)
def sanitize_name(name: str) -> str:
"""
Sanitize a name by removing all non-letter characters except hyphens and Scandinavian letters.
"""
# Replace Scandinavian letters
name = name.replace('ä', 'a').replace('ö', 'o')
name = name.replace('Ä', 'A').replace('Ö', 'O')
# Remove all non-letter characters except hyphens
return ''.join(c for c in name if c.isalpha() or c == '-')
def add_connection(root: ET.Element, name: str, attr_list: list[str], description: str = "Default description") -> ET.Element:
"""
Add a new connection parameter to the XML configuration.
Args:
root (ET.Element): The root element of the XML configuration.
name (str): The name of the connection parameter.
attr_list (list[str]): List of attributes for the connection parameter.
description (str, optional): The description of the connection parameter. Defaults to "Default description".
Returns:
ET.Element: The modified root element with the new connection parameter added.
"""
connection_parameters = root.find("ConnectionParameters")
if connection_parameters is None:
connection_parameters = ET.SubElement(root, "ConnectionParameters")
ET.SubElement(connection_parameters, "ConnectionParameter", Name=f"VarhaUrl{name}", Description=f"Codeserver url for {description}")
initialization = root.find("Initialization")
if initialization is not None:
predefined_commands = initialization.find("PredefinedCommands")
if predefined_commands is None:
predefined_commands = ET.SubElement(initialization, "PredefinedCommands")
ET.SubElement(predefined_commands, "Command", Name=f"Get-AllCodeServerPages{name}")
ET.SubElement(predefined_commands, "Command", Name=f"Get-CodeServerObject{name}")
schema = root.find("Schema")
if schema is not None:
new_class = ET.SubElement(schema, "Class", Name=f"CodeServerObject{name}")
properties = ET.SubElement(new_class, "Properties")
property = ET.SubElement(properties, "Property", Name="conceptCodeId", DataType="String", IsMultivalue="false", IsAutoFill="false", IsUniqueKey="true")
return_binding = ET.SubElement(property, "ReturnBindings")
ET.SubElement(return_binding, "Bind", CommandResultOf=f"Get-AllCodeServerPages{name}", Path="conceptCodeId")
ET.SubElement(return_binding, "Bind", CommandResultOf=f"Get-CodeServerObject{name}", Path="conceptCodeId")
mapping = ET.SubElement(property, "CommandMappings")
ET.SubElement(mapping, "Map", ToCommand=f"Get-CodeServerObject{name}", Parameter="conceptCodeId")
for attr in attr_list:
property = ET.SubElement(properties, "Property", Name=sanitize_name(attr), DataType="String", IsMultivalue="false", IsAutoFill="false")
return_binding = ET.SubElement(property, "ReturnBindings")
ET.SubElement(return_binding, "Bind", CommandResultOf=f"Get-AllCodeServerPages{name}", Path=sanitize_name(attr))
ET.SubElement(return_binding, "Bind", CommandResultOf=f"Get-CodeServerObject{name}", Path=sanitize_name(attr))
read_configuration = ET.SubElement(new_class, "ReadConfiguration")
listing_command = ET.SubElement(read_configuration, "ListingCommand", Command=f"Get-AllCodeServerPages{name}")
ET.SubElement(listing_command, "SetParameter", Param="Resource", Source="ConnectionParameter", Value=f"VarhaUrl{name}")
ET.SubElement(listing_command, "SetParameter", Param="RootProperty", Source="FixedValue", Value="conceptCodes")
cmd_squence = ET.SubElement(read_configuration, "CommandSequence")
item = ET.SubElement(cmd_squence, "Item", Command=f"Get-CodeServerObject{name}", Order="1")
ET.SubElement(item, "SetParameter", Param="Resource", Source="ConnectionParameter", Value=f"VarhaUrl{name}")
ET.SubElement(item, "SetParameter", Param="RootProperty", Source="FixedValue", Value="conceptCodes")
return root
def _generate_xml_configuration() -> ET.Element:
"""
Generate a default XML configuration for a PowerShell connector.
Returns:
ET.Element: The root element of the XML configuration.
"""
root = ET.Element("PowershellConnectorDefinition", Id="CodeServerConnector", Version="0.1", Description="CodeServer REST api connector")
ET.SubElement(root, "PluginAssemblies")
ET.SubElement(root, "ConnectionParameters")
initialization = ET.SubElement(root, "Initialization")
ET.SubElement(initialization, "PredefinedCommands")
custom_commands = ET.SubElement(initialization, "CustomCommands")
cmd = ET.SubElement(custom_commands, "CustomCommand", Name="Initialize-CodeServer")
cmd.text = ET.CDATA(r"""param (
)
Import-Module D:\bin\VSHVA\PowerShell\CodeServerConnector.psm1""")
environment_initialization = ET.SubElement(initialization, "EnvironmentInitialization")
connect = ET.SubElement(environment_initialization, "Connect")
command_sequence = ET.SubElement(connect, "CommandSequence")
ET.SubElement(command_sequence, "Item", Command="Initialize-CodeServer", Order="1")
ET.SubElement(environment_initialization, "Disconnect")
ET.SubElement(root, "Schema")
return root
def get_xml_data(xml_file: Path) -> ET.Element:
"""
Get XML data from a file. If the file does not exist, generate a default configuration.
Args:
xml_file (Path): The path to the XML file.
Returns:
ET.Element: The root element of the XML configuration.
"""
if not xml_file.exists():
return _generate_xml_configuration()
try:
parser = ET.XMLParser(strip_cdata=False)
tree = ET.parse(xml_file, parser=parser)
return tree
except ET.XMLSyntaxError as e:
raise click.FileError(xml_file, f"Not a valid XML file. {e}")