Skip to content
Snippets Groups Projects
Commit 69c7d261 authored by Kristina Mazur's avatar Kristina Mazur
Browse files

Enhance it

parent 762694f6
No related branches found
No related tags found
No related merge requests found
#!python
# Copyright (c) 2023 S. Oberschwendtner.
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""! @brief Script for converting an aircraft XML file to a content page."""
##
# @file document_aircraft_xml.py
#
# @brief Script for converting an aircraft XML file to a content page for the UNICADO homepage.
#
# @section description_document_aircraft_xml Description
# This script parse the entries of an aircraft XML file and extracts
# the entries and documents them using their description tags.
# The output is a markdown file which can be used for the documentation.
#
# @section libraries_document_aircraft_xml Libraries/Modules
# - argparse standard library (https://docs.python.org/3/library/argparse.html)
# - Parser for command-line options, arguments and sub-commands.
# - xml standard library (https://docs.python.org/3/library/xml.html)
# - XML Processing Modules.
# - pathlib standard library (https://docs.python.org/3/library/pathlib.html)
# - Object-oriented filesystem paths.
#
# @section notes_document_aircraft_xml Notes
# - None.
#
# @section todo_document_aircraft_xml TODO
# - None.
#
# @section authors_document_aircraft_xml Author(s)
# - Created by S. Oberschwendtner on 19/09/2023.
# === Imports ===
import argparse
import xml.etree.ElementTree as ET
from pathlib import Path
# === Configuration ===
# Define the format of the output
FORMAT = {
"Header": "\n## {:s}\n> **Description**: {:s}\n",
"Header": "\n{}## {:s}\n> **Description**: {:s}\n",
"Unit": "> **Unit**: {:s}\n",
"TableHeader": "| Relative XML Path | Unit | Description |\n|:---|:---:|:---|",
"Table": "| <nobr>`{:s}` | *{:s}* | {:s} |",
}
# Which keys are used in the XML attributes for which information
KEYS = {
"Description": "description", # Match the 'description' key from XML
"Unit": "unit", # Match the 'unit' key from XML
"Description": "description",
"Unit": "unit",
}
# Define specific levels for each child node of "requirements_and_specifications"
CUSTOM_LEVELS = {
"general": 2,
"mission_files": 2,
"design_specification": 4,
"requirements": 3,
}
# === Classes ===
class Page:
"""Class for a page.
A page is one top section of the aircraft XML file.
"""
@property
def max_level_reached(self) -> bool:
"""Returns whether the maximum level has been reached."""
return self.current_level >= self.max_header_level
def __init__(self, title, max_level):
"""Constructor of the class.
Args:
title (str): Title of the page.
max_level (int): Maximum level of the headers.
"""
def __init__(self, title):
self.title = title
self.max_header_level = max_level
self.current_level = 0
self.table_started = False
self.current_path = Path(".")
self.sections = [[]]
def create(self, node: ET.Element):
"""Creates the page from the given node, summarizing nested elements properly.
Args:
node (ET.Element): Node to start from.
"""
# Add header if appropriate
if not self.max_level_reached:
def create(self, node: ET.Element, level=None):
# Set the level based on custom levels if provided
if node.tag in CUSTOM_LEVELS:
level = CUSTOM_LEVELS[node.tag]
elif level is None:
level = self.current_level + 1
# Update current level and path
if level <= 4:
self.current_level = level
self.current_path /= node.tag
# Add header if appropriate
self.make_header_entry(node)
# Treat node attributes and values as part of the parent row
......@@ -110,28 +55,25 @@ class Page:
# Process child elements recursively, skipping common attributes like 'value', 'unit', etc.
for child in node:
if child.tag in ["value", "unit", "lower_boundary", "upper_boundary"]:
continue
self.create(child)
if child.tag not in ["value", "unit", "lower_boundary", "upper_boundary"]:
self.create(child, level + 1)
# Restore previous path after processing
self.current_path = self.current_path.parent
def make_header_entry(self, node: ET.Element):
"""Creates a header entry.
Args:
node (ET.Element): The current node element.
"""
# Reset the table when creating a new header
self.table_started = False
# Fetch description
# Fetch description and adjust header level format
description = node.attrib.get(KEYS["Description"], "None")
header_level_prefix = "#" * min(self.current_level, 4)
# Create the header with description
print(
"\n"
+ self.current_level * "#"
+ FORMAT["Header"].format(node.tag, description)
+ header_level_prefix
+ FORMAT["Header"].format(self.current_level, node.tag, description)
)
# Try to add a unit description
......@@ -140,11 +82,6 @@ class Page:
print(FORMAT["Unit"].format(unit))
def make_table_entry(self, node: ET.Element):
"""Creates a table entry for the current node, embedding child attributes into the parent node's row.
Args:
node (ET.Element): The current node element.
"""
# Check if the table has already been started
if not self.table_started:
self.table_started = True
......@@ -153,29 +90,14 @@ class Page:
# Generate a relative XML path for the current node
path_name = str(self.current_path / node.tag).replace("\\", "/")
# Fetch parent description and unit
# Fetch the description and unit
description = node.attrib.get(KEYS["Description"], f"No description for {node.tag}")
unit = node.attrib.get(KEYS["Unit"], "No unit specified")
# Collect all child attributes
child_details = []
for child in node:
child_desc = child.attrib.get(KEYS["Description"], f"No description for {child.tag}")
child_unit = child.attrib.get(KEYS["Unit"], "No unit specified")
child_details.append(f"{child.tag}: {child_desc} (unit: {child_unit})")
# Combine parent description with child attributes
combined_description = description + " | " + " | ".join(child_details)
# Print the table row for the parent node
print(FORMAT["Table"].format(path_name, unit, combined_description))
# Print the table row for the current node
print(FORMAT["Table"].format(path_name, unit, description))
# === Main ===
def main():
"""
Main function of the script.
"""
# Create argument parser
parser = argparse.ArgumentParser(
description="Converts an aircraft XML file to a markdown file. The output is streamed to stdout and can be piped to a file."
)
......@@ -192,12 +114,6 @@ def main():
type=str,
help="The title of the output page. This also sets the root node which is used to create the document.",
)
parser.add_argument(
"--level",
metavar="level",
type=int,
help="The maximum level nodes to be used as headers.",
)
# Parse the arguments
args = parser.parse_args()
......@@ -207,7 +123,7 @@ def main():
root = tree.getroot()
# Get the configuration parameters
page = Page(args.title, args.level)
page = Page(args.title)
node = root.find(page.title)
# Check whether the node exists
......@@ -217,6 +133,5 @@ def main():
# Start creating the page
page.create(node)
if __name__ == "__main__":
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment