{"id":11067,"date":"2023-11-18T19:29:07","date_gmt":"2023-11-18T10:29:07","guid":{"rendered":"https:\/\/www.sambuichi.jp\/?p=11067"},"modified":"2023-11-28T19:31:07","modified_gmt":"2023-11-28T10:31:07","slug":"automating-uml-diagram-creation-from-csv-with-python-and-plantuml","status":"publish","type":"post","link":"https:\/\/www.sambuichi.jp\/?p=11067&lang=en","title":{"rendered":"Streamlining UML Diagram Automation for ISO 21378 Audit Data Collection"},"content":{"rendered":"<p>Views: 45<\/p><div id=\"header\">\n<h1>Streamlining UML Diagram Automation for ISO 21378 Audit Data Collection: Integrating Python and PlantUML with CSV<\/h1>\n<div id=\"toc\" class=\"toc2\">\n<div id=\"toctitle\">Table of Contents<\/div>\n<ul class=\"sectlevel1\">\n<li><a href=\"#_introduction\">1. Introduction<\/a><\/li>\n<li><a href=\"#_objective\">2. Objective<\/a><\/li>\n<li><a href=\"#_tool_and_environment_setup\">3. Tool and Environment Setup<\/a><\/li>\n<li><a href=\"#_building_the_python_script_and_its_functions\">4. Building the Python Script and Its Functions<\/a><\/li>\n<li><a href=\"#_understanding_the_csv_input_format\">5. Understanding the CSV Input Format<\/a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_object_class\">5.1. object_class<\/a><\/li>\n<li><a href=\"#_target_classes_file\">5.2. target_classes_file<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#_usage\">6. Usage<\/a><\/li>\n<li><a href=\"#_conclusion\">7. Conclusion<\/a><\/li>\n<li><a href=\"#_uml_class_diagrams_for_iso_213782019_audit_data_collection\">8. UML Class Diagrams for ISO 21378:2019 Audit data collection<\/a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_sales_module\">8.1. Sales module<\/a><\/li>\n<li><a href=\"#_accounts_receivable_module\">8.2. Accounts Receivable module<\/a><\/li>\n<li><a href=\"#_purchase_module\">8.3. Purchase module<\/a><\/li>\n<li><a href=\"#_accounts_payable_module\">8.4. Accounts Payable module<\/a><\/li>\n<li><a href=\"#_general_ledger_module\">8.5. General Ledger module<\/a><\/li>\n<li><a href=\"#_inventory_module\">8.6. Inventory module<\/a><\/li>\n<li><a href=\"#_ppe_module\">8.7. PPE module<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#_source_code\">9. Source Code<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n<div id=\"content_adoc\">\n<div id=\"preamble\">\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Nobuyuki SAMBUICHI<br \/>\n<a href=\"https:\/\/www.iso.org\/committee\/5648297.html\">ISO\/TC295 Audit data services<\/a><br \/>\nConvener at SG1 Semantic model<br \/>\nCo-project Leader at AWI 21926 Semantic data model for audit data services<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_introduction\">1. Introduction<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>In today&#8217;s digital world, visual representation of data models is crucial. This blog explains how to automate UML (Unified Modeling Language) diagrams creation from CSV (Comma Separated Values) files using Python and PlantUML.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_objective\">2. Objective<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Our primary goal is to transform class information stored in CSV files into structured UML diagrams, useful for software developers and system architects.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_tool_and_environment_setup\">3. Tool and Environment Setup<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>To begin, ensure you have Python installed. Then, set up PlantUML:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><strong>Download PlantUML<\/strong>: Go to <a href=\"http:\/\/www.plantuml.com\">PlantUML official website<\/a> and download <code>plantuml.jar<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>Install Java<\/strong>: PlantUML requires Java. Download and install the Java Runtime Environment (JRE).<\/p>\n<\/li>\n<li>\n<p><strong>Verify PlantUML Setup<\/strong>: Run <code>java -jar path\/to\/plantuml.jar -version<\/code> in your terminal. Replace <code>path\/to\/plantuml.jar<\/code> with your PlantUML jar file path.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_building_the_python_script_and_its_functions\">4. Building the Python Script and Its Functions<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>The Python script is designed to automate the UML diagram creation process by performing several key functions:<\/p>\n<\/div>\n<div class=\"olist arabic\">\n<ol class=\"arabic\">\n<li>\n<p><strong>Path Conversion<\/strong>: Converts relative paths to absolute paths for reliable file access.<\/p>\n<\/li>\n<li>\n<p><strong>Reading Target Classes<\/strong>: Reads specific class names from <code>target_classes_file<\/code> to selectively generate UML diagrams based on user-defined criteria.<\/p>\n<\/li>\n<li>\n<p><strong>Parsing CSV Data<\/strong>: Extracts essential class properties and relationships from <code>object_class<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>Generating PlantUML Code<\/strong>: Transforms extracted data into PlantUML syntax, setting the stage for diagram generation.<\/p>\n<\/li>\n<li>\n<p><strong>Exporting to UML Diagram<\/strong>: Writes the PlantUML code to a file and employs PlantUML to convert this code into a visual UML diagram.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<div class=\"paragraph\">\n<p>This script, by processing only relevant data from <code>mim.csv<\/code> and <code>target_classes_file<\/code>, efficiently creates focused and accurate UML diagrams, enhancing the understanding and representation of complex semantic models.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_understanding_the_csv_input_format\">5. Understanding the CSV Input Format<\/h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"_object_class\">5.1. object_class<\/h3>\n<div class=\"paragraph\">\n<p>The object_class file, used as input, is a Refined Message Information Model (R-MIM) for HL7 graphwalk, aimed at producing Hierarchical Message Definition (HMD). The file contains the following columns:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><strong>ID<\/strong>: A unique identifier for each entry.<\/p>\n<\/li>\n<li>\n<p><strong>Type<\/strong>: The type of the entry, such as attribute, association, etc.<\/p>\n<\/li>\n<li>\n<p><strong>Level<\/strong>: The hierarchical level of the entry in the model.<\/p>\n<\/li>\n<li>\n<p><strong>Multiplicity<\/strong>: Defines the multiplicity of the relationship.<\/p>\n<\/li>\n<li>\n<p><strong>ClassName<\/strong>: The name of the class.<\/p>\n<\/li>\n<li>\n<p><strong>AttributeName<\/strong>: The name of the attribute.<\/p>\n<\/li>\n<li>\n<p><strong>Datatype<\/strong>: The datatype of the attribute.<\/p>\n<\/li>\n<li>\n<p><strong>AssociatedClass<\/strong>: Any class that is associated with the current entry.<\/p>\n<\/li>\n<li>\n<p><strong>Description<\/strong>: A brief description of the entry.<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>It&#8217;s important to note that the Python script utilizes only a subset of these columns &#8211; specifically ClassName, AttributeName, Type, Datatype, and AssociatedClass, to construct the UML diagrams.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>Ensure the CSV file follows this format for the script to parse and generate UML diagrams correctly.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>The Python script specifically processes the following columns from object_class file:<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><strong>ClassName<\/strong>: Utilized to identify and create UML classes.<\/p>\n<\/li>\n<li>\n<p><strong>AttributeName<\/strong>: Used to define attributes within each UML class.<\/p>\n<\/li>\n<li>\n<p><strong>Type<\/strong>: Indicates the nature of the entry, whether it&#8217;s an attribute or a type of relationship (like association or aggregation).<\/p>\n<\/li>\n<li>\n<p><strong>Datatype<\/strong>: Specifies the data type of attributes in the UML class.<\/p>\n<\/li>\n<li>\n<p><strong>AssociatedClass<\/strong>: Important for defining relationships between classes, especially in cases of associations, aggregations, and compositions.<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>These columns are essential for accurately mapping the R-MIM data into a structured UML diagram, capturing the necessary details for each class and their inter-relationships.<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_target_classes_file\">5.2. target_classes_file<\/h3>\n<div class=\"paragraph\">\n<p>The object_class file, integral to this semantic model, encompasses a range of classes related to the Refined Message Information Model (R-MIM) for HL7. To selectively generate UML class diagrams, the <code>target_classes_file<\/code> is utilized. This file contains a list of class names, with each class name written on a separate row. The Python script reads this file to filter and process only the specified classes from <code>mim.csv<\/code>, enabling focused and relevant UML diagram generation based on the user&#8217;s requirements.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_usage\">6. Usage<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Prepare your CSV with class information, then run the Python script to generate the UML diagram.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_conclusion\">7. Conclusion<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>This automation simplifies creating UML diagrams from CSV files, showcasing the synergy between Python&#8217;s simplicity and PlantUML&#8217;s efficiency.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_uml_class_diagrams_for_iso_213782019_audit_data_collection\">8. UML Class Diagrams for ISO 21378:2019 Audit data collection<\/h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"_sales_module\">8.1. Sales module<\/h3>\n<div class=\"paragraph\">\n<p>To enlarge, right-click and select &#8220;Open image in new tab.&#8221;<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img\n<img decoding=\"async\" src=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2023\/11\/SAL_UML-2.png\" alt=\"SAL UML 1\">\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_accounts_receivable_module\">8.2. Accounts Receivable module<\/h3>\n<div class=\"paragraph\">\n<p>To enlarge, right-click and select &#8220;Open image in new tab.&#8221;<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2023\/11\/AR_UML-2.png\" alt=\"AR UML 1\">\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_purchase_module\">8.3. Purchase module<\/h3>\n<div class=\"paragraph\">\n<p>To enlarge, right-click and select &#8220;Open image in new tab.&#8221;<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2023\/11\/PUR_UML-2.png\" alt=\"PUR UML 1\">\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_accounts_payable_module\">8.4. Accounts Payable module<\/h3>\n<div class=\"paragraph\">\n<p>To enlarge, right-click and select &#8220;Open image in new tab.&#8221;<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2023\/11\/AP_UML-2.png\" alt=\"AP UML 1\">\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_general_ledger_module\">8.5. General Ledger module<\/h3>\n<div class=\"paragraph\">\n<p>To enlarge, right-click and select &#8220;Open image in new tab.&#8221;<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2023\/11\/GL_UML-2.png\" alt=\"GL UML 1\">\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_inventory_module\">8.6. Inventory module<\/h3>\n<div class=\"paragraph\">\n<p>To enlarge, right-click and select &#8220;Open image in new tab.&#8221;<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2023\/11\/INV_UML-2.png\" alt=\"INV UML 1\">\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_ppe_module\">8.7. PPE module<\/h3>\n<div class=\"paragraph\">\n<p>To enlarge, right-click and select &#8220;Open image in new tab.&#8221;<\/p>\n<\/div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2023\/11\/PPE_UML-2.png\" alt=\"PPE UML\">\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_source_code\">9. Source Code<\/h2>\n<div class=\"sectionbody\">\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">#!\/usr\/bin\/env python3\r\n# coding: utf-8\r\n#\r\n# automate UML (Unified Modeling Language) diagrams creation from CSV\r\n# (Comma Separated Values) files using Python and PlantUM\r\n#\r\n# designed by SAMBUICHI, Nobuyuki (Sambuichi Professional Engineers Office)\r\n# written by SAMBUICHI, Nobuyuki (Sambuichi Professional Engineers Office)\r\n#\r\n# MIT License\r\n#\r\n# (c) 2023 SAMBUICHI Nobuyuki (Sambuichi Professional Engineers Office)\r\n#\r\n# Permission is hereby granted, free of charge, to any person obtaining a copy\r\n# of this software and associated documentation files (the \"Software\"), to deal\r\n# in the Software without restriction, including without limitation the rights\r\n# to use, copy, modify, merge, publish, distribute, sublicense, and\/or sell\r\n# copies of the Software, and to permit persons to whom the Software is\r\n# furnished to do so, subject to the following conditions:\r\n#\r\n# The above copyright notice and this permission notice shall be included in all\r\n# copies or substantial portions of the Software.\r\n#\r\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n# SOFTWARE.\r\nimport csv\r\nimport os\r\nimport subprocess\r\nimport re\r\n\r\nSEP = os.sep  # Define the system-specific path separator\r\n\r\n# Function to convert a given path to an absolute path\r\ndef file_path(pathname):\r\n    if SEP == pathname[0:1]:\r\n        return pathname\r\n    else:\r\n        pathname = pathname.replace('\/', SEP)\r\n        dir = os.path.dirname(__file__)\r\n        new_path = os.path.join(dir, pathname)\r\n        return new_path\r\n\r\n# Function to load target class names from a file\r\ndef load_target_classes(file_path):\r\n    with open(file_path, 'r', encoding='utf-8-sig') as file:\r\n        return [line.strip() for line in file if line.strip()]\r\n\r\n# Function to parse a CSV file and generate UML code\r\ndef parse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules):\r\n    classes       = {}\r\n    relationships = []\r\n    object_class  = file_path(f\"{source}{object_class}\")\r\n    uml_file_path = file_path(f\"{source}{uml_file_path}\")\r\n\r\n    with open(object_class, 'r', encoding='utf-8-sig') as file:\r\n        reader = csv.reader(file)\r\n        next(reader)  # Skip the header row\r\n        target_class = []\r\n        for row in reader:\r\n            # Skip empty rows\r\n            if not row or not any(row):\r\n                continue\r\n            # Extract and strip values from the row\r\n            id, prop_type, level, multiplicity, class_name, prop_name, data_type, assoc_class, description = [x.strip() for x in row]\r\n            pattern = r'([A-Z]+)[0-9]+'\r\n            match = re.search(pattern, id)\r\n            module = None\r\n            if match:\r\n                module = match.group(1)\r\n            if module in target_modules:\r\n                if class_name and class_name not in target_class:\r\n                    target_class.append(class_name)\r\n                if assoc_class and assoc_class not in target_class:\r\n                    target_class.append(assoc_class)\r\n\r\n    with open(object_class, 'r', encoding='utf-8-sig') as file:\r\n        reader = csv.reader(file)\r\n        next(reader)  # Skip the header row\r\n\r\n        for row in reader:\r\n            # Skip empty rows\r\n            if not row or not any(row):\r\n                continue\r\n\r\n            # Extract and strip values from the row\r\n            id, prop_type, level, multiplicity, class_name, prop_name, data_type, assoc_class, description = [x.strip() for x in row]\r\n            if class_name in target_class:\r\n                if class_name and class_name not in classes:\r\n                    classes[class_name] = {\"attributes\": []}\r\n                elif assoc_class and assoc_class not in classes:\r\n                    classes[assoc_class] = {\"attributes\": []}\r\n\r\n                # Handle attributes and relationships\r\n                if 'Attribute' in prop_type:\r\n                    # Additional handling for primary key attribute\r\n                    if 'PK' in prop_type:\r\n                        classes[class_name][\"attributes\"].append(f'+PK: {prop_name} : {data_type} ')\r\n                    else:\r\n                        classes[class_name][\"attributes\"].append(f'+{prop_name} : {data_type}')\r\n                elif prop_type in ['Association', 'Aggregation', 'Composition', 'Specialized Class']:\r\n                    # Determine the relationship symbol based on the property type\r\n                    if prop_type == 'Association':\r\n                        relation_symbol = '--'\r\n                    elif prop_type == 'Aggregation':\r\n                        relation_symbol = 'o--'\r\n                    elif prop_type == 'Composition':\r\n                        relation_symbol = '*--'\r\n                    elif prop_type == 'Specialized Class':\r\n                        relation_symbol = '--|&gt;'\r\n                    relation = f'\"{class_name}\" {relation_symbol} \"{assoc_class}\" : {prop_name}'\r\n                    relationships.append(relation)\r\n\r\n    uml_code = '@startuml\\n'\r\n    # Build UML code for each class\r\n    for class_name, properties in classes.items():\r\n        if not class_name:\r\n            continue\r\n        uml_code += f'class \"{class_name}\" {{\\n'\r\n        for attr in properties[\"attributes\"]:\r\n            uml_code += f'    {attr}\\n'\r\n        uml_code += '}\\n\\n'\r\n\r\n    # Add relationships to UML code\r\n    for relation in relationships:\r\n        uml_code += relation + '\\n'\r\n\r\n    uml_code += '@enduml'\r\n\r\n    # Write the resulting UML code to a text file\r\n    with open(uml_file_path, 'w') as f:\r\n        f.write(uml_code)\r\n\r\n    # Function to generate UML image using PlantUML\r\n# def generate_uml_image(plantuml_path, uml_file_path):\r\n    subprocess.run([\"java\", \"-DPLANTUML_LIMIT_SIZE=16384\", \"-jar\", plantuml_path, uml_file_path])\r\n\r\n# Main execution: Setting up paths and generating UML code and image\r\nplantuml_path = file_path('UML\/bin\/plantuml-mit-1.2023.12.jar')\r\nsource = 'UML\/'\r\nobject_class = 'source\/mim.csv'\r\n\r\n# Generate UML from CSV and then create the image\r\n# Sales module\r\ntarget_modules =  ['SAL','GEN','BS']\r\numl_file_path = 'diagram\/SAL_UML.txt'\r\nparse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules)\r\nprint(uml_file_path)\r\n\r\n# Accounts Receivable module\r\ntarget_modules =  ['AR','GEN','BS']\r\numl_file_path = 'diagram\/AR_UML.txt'\r\nparse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules)\r\nprint(uml_file_path)\r\n\r\n# Purchase module\r\ntarget_modules =  ['PUR','GEN','BS']\r\numl_file_path = 'diagram\/PUR_UML.txt'\r\nparse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules)\r\nprint(uml_file_path)\r\n\r\n# Accounts Payable module\r\ntarget_modules =  ['AP','GEN','BS']\r\numl_file_path = 'diagram\/AP_UML.txt'\r\nparse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules)\r\nprint(uml_file_path)\r\n\r\n# General Ledger module\r\ntarget_modules =  ['GL','GEN','BS']\r\numl_file_path = 'diagram\/GL_UML.txt'\r\nparse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules)\r\nprint(uml_file_path)\r\n\r\n# Inventory module\r\ntarget_modules =  ['INV','GEN','BS']\r\numl_file_path = 'diagram\/INV_UML.txt'\r\nparse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules)\r\nprint(uml_file_path)\r\n\r\n# PPE module\r\ntarget_modules =  ['PPE','GEN','BS']\r\numl_file_path = 'diagram\/PPE_UML.txt'\r\nparse_csv_to_uml(plantuml_path, source, object_class, uml_file_path, target_modules)\r\nprint(uml_file_path)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div id=\"footer\">\n<div id=\"footer-text\">\nLast updated 2023-11-19 10:17:01 +0900\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Views: 45 Streamlining UML Diagram Automation for ISO 21378 Audit Data Collection: Integrating Python and Plan [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":11044,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[32],"tags":[],"_links":{"self":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/11067"}],"collection":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=11067"}],"version-history":[{"count":12,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/11067\/revisions"}],"predecessor-version":[{"id":11177,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/11067\/revisions\/11177"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/media\/11044"}],"wp:attachment":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=11067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=11067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=11067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}