Each request to a large language model (LLM) can be viewed as consisting of two components: a static part known as the "prompt" and a dynamic part referred to as the "query."

We will use the same prompt and query with four different language models to generate Python code that will transform XML into a more user-friendly HTML format.

Query

Here is our query in reStructuredText format:

List of Raspberry Pi Hotkeys
----------------------------

Keyboard shortcuts can be found in ``/etc/xdg/openbox/lxde-pi-rc.xml`` file on
Raspberry Pi. We need to extract list of ``keybind`` records at ``/openbox_config/keyboard`` xpath.
Each record looks like this:

.. code:: xml

    <keybind key="C-S-Escape">
      <action name="Execute">
        <command>lxtask</command>
      </action>
    </keybind>

Create HTML file with an output that contains HTML file with 2 columns: ``key`` and ``action name``.

Prompt

Here is our prompt.

Generate Python code based on the provided reStructuredText (reST) description. The code should precisely implement the functionality or requirements described in the reST, adhering to best practices in Python programming. Ensure that the code is efficient, readable, and well-structured, including appropriate comments and docstrings where necessary. The implementation should handle edge cases and input validation as described or implied by the reST. If applicable, include example usage or test cases.

Claude Sonnet 3.5 using web UI

Here is the result from Claude Sonnet 3.5:

import xml.etree.ElementTree as ET
import os

def extract_hotkeys(file_path):
    """
    Extract hotkey information from the given XML file.

    Args:
        file_path (str): Path to the XML file.

    Returns:
        list: List of dictionaries containing key and action information.
    """
    try:
        tree = ET.parse(file_path)
        root = tree.getroot()

        # Find all keybind elements
        keybinds = root.findall(".//keyboard/keybind")  (1)

        hotkeys = []
        for keybind in keybinds:
            key = keybind.get('key')
            action = keybind.find(".//action")
            if action is not None:
                action_name = action.get('name')
                hotkeys.append({'key': key, 'action': action_name})

        return hotkeys
    except ET.ParseError:
        print(f"Error parsing XML file: {file_path}")
        return []
    except FileNotFoundError:
        print(f"File not found: {file_path}")
        return []

def generate_html(hotkeys):
    """
    Generate HTML content from the extracted hotkey information.

    Args:
        hotkeys (list): List of dictionaries containing key and action information.

    Returns:
        str: HTML content as a string.
    """
    html_content = """
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Raspberry Pi Hotkeys</title>
        <style>
            table {
                border-collapse: collapse;
                width: 100%;
            }
            th, td {
                border: 1px solid black;
                padding: 8px;
                text-align: left;
            }
            th {
                background-color: #f2f2f2;
            }
        </style>
    </head>
    <body>
        <h1>Raspberry Pi Hotkeys</h1>
        <table>
            <tr>
                <th>Key</th>
                <th>Action Name</th>
            </tr>
    """

    for hotkey in hotkeys:
        html_content += f"""
            <tr>
                <td>{hotkey['key']}</td>
                <td>{hotkey['action']}</td>
            </tr>
        """

    html_content += """
        </table>
    </body>
    </html>
    """

    return html_content

def main():
    file_path = "/etc/xdg/openbox/lxde-pi-rc.xml"
    output_file = "raspberry_pi_hotkeys.html"

    hotkeys = extract_hotkeys(file_path)

    if hotkeys:
        html_content = generate_html(hotkeys)

        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(html_content)

        print(f"HTML file '{output_file}' has been generated successfully.")
    else:
        print("No hotkeys were extracted. Please check the input file and its permissions.")

if __name__ == "__main__":
    main()
1 Unexpectedly, keybinds was empty here, due to the namespace declared in XML file.
Failing to specify the XML namespace when using a Python parser means that you will be operating within the default XML namespace. As a result, you may not be able to access XML elements in your file that are associated with a specific namespace.

In our file, the XML namespace was declared in the following way:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file, it will be overwritten on install.
        Copy the file to $HOME/.config/openbox/ instead. -->
<openbox_config xmlns="http://openbox.org/3.4/rc">           (1)
  <resistance>
    <strength>10</strength>
    <screen_edge_strength>20</screen_edge_strength>
  </resistance>
  <focus>
    <focusNew>yes</focusNew>
    ...
  </focus>
  ...
  <keyboard>                                                 (2)
    <chainQuitKey>C-g</chainQuitKey>
    <!-- Keybindings for desktop switching -->
    <keybind key="C-A-Left">
      <action name="UnmaximizeFull"/>                        (3)
      <action name="MaximizeVert"/>
      <action name="MoveResizeTo">
        <width>50%</width>
      </action>
      <action name="MoveToEdge"><direction>west</direction></action>
    </keybind>
    <keybind key="C-A-Right">
      <action name="UnmaximizeFull"/>
      <action name="MaximizeVert"/>
      <action name="MoveResizeTo">
        <width>50%</width>
      </action>
      <action name="MoveToEdge"><direction>east</direction></action>
    </keybind>
    ...
  </keyboard>
  ...
</openbox_config>
1 Here is namespace declaration in xmlns attribute
2 Here are our hotkey declarations
3 Note that actually there can be many actions in keybind.

Gemini 1.5 Flash using web UI

Here is the result from Gemini 1.5 Flash:

import xml.etree.ElementTree as ET
import os

def extract_hotkeys(xml_file):
  """Extracts hotkey information from an XML file.

  Args:
    xml_file: Path to the XML file.

  Returns:
    A list of tuples, where each tuple contains (key, action_name).
  """

  tree = ET.parse(xml_file)
  root = tree.getroot()

  hotkeys = []
  for keybind in root.findall('./openbox_config/keyboard/keybind'):  (1)
    key = keybind.get('key')
    action_name = keybind.find('action').get('name')
    hotkeys.append((key, action_name))

  return hotkeys

def generate_html(hotkeys):
  """Generates an HTML table from the extracted hotkey data.

  Args:
    hotkeys: A list of tuples, where each tuple contains (key, action_name).
  """

  html = """
  <!DOCTYPE html>
  <html>
  <head>
    <title>Raspberry Pi Hotkeys</title>
  </head>
  <body>
    <table>
      <tr>
        <th>Key</th>
        <th>Action</th>
      </tr>
  """

  for key, action in hotkeys:
    html += f"<tr><td>{key}</td><td>{action}</td></tr>"

  html += """
    </table>
  </body>
  </html>
  """

  with open('hotkeys.html', 'w') as f:
    f.write(html)

if __name__ == '__main__':
  xml_file = '/etc/xdg/openbox/lxde-pi-rc.xml'
  hotkeys = extract_hotkeys(xml_file)
  generate_html(hotkeys)
1 XML namespace is not expected here as well.

OpenAI gpt-4o using web UI

Here is the result from OpenAI gpt-4o:

import xml.etree.ElementTree as ET
import os

def parse_keybinds(xml_file):
    """
    Parses the keybind records from the specified XML file and returns a list of tuples.
    Each tuple contains the key and the corresponding action name.

    Args:
        xml_file (str): Path to the XML file to parse.

    Returns:
        list: List of tuples containing key and action name.
    """
    if not os.path.exists(xml_file):
        raise FileNotFoundError(f"The file {xml_file} does not exist.")

    tree = ET.parse(xml_file)
    root = tree.getroot()

    # Find the namespace (if any) in the XML
    namespace = ''                                  (1)
    if root.tag.startswith('{'):
        namespace = root.tag.split('}')[0] + '}'

    keybinds = []
    for keybind in root.findall(f".//{namespace}keybind"):
        key = keybind.attrib.get('key')
        action = keybind.find(f"./{namespace}action").attrib.get('name')
        keybinds.append((key, action))

    return keybinds

def generate_html(keybinds, output_file):
    """
    Generates an HTML file with two columns: key and action name.

    Args:
        keybinds (list): List of tuples containing key and action name.
        output_file (str): Path to the HTML file to generate.
    """
    html_content = """<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Raspberry Pi Hotkeys</title>
    <style>
        table {
            width: 50%;
            border-collapse: collapse;
            margin: 25px 0;
            font-size: 18px;
            text-align: left;
        }
        th, td {
            padding: 12px;
            border-bottom: 1px solid #ddd;
        }
        th {
            background-color: #f2f2f2;
        }
    </style>
</head>
<body>
    <h1>Raspberry Pi Hotkeys</h1>
    <table>
        <tr>
            <th>Key</th>
            <th>Action Name</th>
        </tr>
"""

    for key, action in keybinds:
        html_content += f"        <tr><td>{key}</td><td>{action}</td></tr>\n"

    html_content += """    </table>
</body>
</html>"""

    with open(output_file, 'w') as file:
        file.write(html_content)
    print(f"HTML file '{output_file}' has been created successfully.")

def main():
    xml_file = '/etc/xdg/openbox/lxde-pi-rc.xml'
    output_file = 'raspberry_pi_hotkeys.html'

    # Parse keybinds from the XML file
    keybinds = parse_keybinds(xml_file)

    # Generate the HTML file
    generate_html(keybinds, output_file)

if __name__ == "__main__":
    main()
1 Namespace support is provided, and the generated code works seamlessly right from the start.

OpenAI gpt-4o-mini using API

Here is the result from OpenAI gpt-4o-mini:

import xml.etree.ElementTree as ET
import html

def extract_keybinds(xml_file):
    """
    Extracts keybind records from the specified XML file.

    Args:
        xml_file (str): The path to the XML file containing keybinds.

    Returns:
        list of tuples: A list of tuples where each tuple contains the key and action name.
    """
    try:
        tree = ET.parse(xml_file)
        root = tree.getroot()

        # Define the namespace if needed (not necessary in this case)          (1)
        # namespaces = {'openbox_config': 'http://openbox.org/3.4/config'}

        keybinds = []

        # Find all keybind elements
        for keybind in root.findall('.//keybind'):
            key = keybind.get('key')
            action = keybind.find('action')
            if action is not None:
                action_name = action.get('name')
                keybinds.append((key, action_name))

        return keybinds

    except ET.ParseError:
        print("Error parsing the XML file. Please check the file format.")
        return []
    except FileNotFoundError:
        print(f"The file {xml_file} was not found.")
        return []
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        return []

def generate_html(keybinds, output_file):
    """
    Generates an HTML file from the list of keybinds.

    Args:
        keybinds (list of tuples): List of tuples containing keybinds.
        output_file (str): The path to the output HTML file.
    """
    html_content = """
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Raspberry Pi Hotkeys</title>
        <style>
            table {
                width: 50%;
                border-collapse: collapse;
                margin: 20px auto;
            }
            th, td {
                border: 1px solid #ddd;
                padding: 8px;
                text-align: left;
            }
            th {
                background-color: #f2f2f2;
            }
        </style>
    </head>
    <body>
        <h2 style="text-align:center;">Raspberry Pi Hotkeys</h2>
        <table>
            <tr>
                <th>Key</th>
                <th>Action Name</th>
            </tr>
    """

    # Populate the table with keybinds
    for key, action_name in keybinds:
        key = html.escape(key)  # Escape HTML special characters            (2)
        action_name = html.escape(action_name)  # Escape HTML special characters
        html_content += f"""
            <tr>
                <td>{key}</td>
                <td>{action_name}</td>
            </tr>
        """

    html_content += """
        </table>
    </body>
    </html>
    """

    # Write the HTML content to the output file
    with open(output_file, 'w') as file:
        file.write(html_content)

def main():
    xml_file = '/etc/xdg/openbox/lxde-pi-rc.xml'  # Update this path based on your environment
    output_file = 'raspberry_pi_hotkeys.html'

    keybinds = extract_keybinds(xml_file)
    if keybinds:
        generate_html(keybinds, output_file)
        print(f"HTML file generated successfully: {output_file}")
    else:
        print("No keybinds found or an error occurred.")

if __name__ == "__main__":
    main()
1 Interestingly enough, gpt-4o-mini mentions the namespace but does not use it, since it was not mentioned in the requirements.
2 gpt-4o-mini was also the only model that escaped HTML characters when generating the HTML file.
Escaping HTML characters such as <, >, & and " is a crucial practice when generating HTML content. This is because even a single unexpected value from input data can disrupt your rendering and potentially compromise the integrity of your webpage. By properly escaping these characters, you ensure that your content is displayed correctly and securely.

Summary

All evaluated LLMs proved to be quite useful, and namespace was not mentioned in our query, but gpt-4o stands out slightly due to its ability to anticipate namespaces when parsing XML files.

Final script version can be found here.