{"id":10235,"date":"2023-06-28T19:34:15","date_gmt":"2023-06-28T10:34:15","guid":{"rendered":"https:\/\/www.sambuichi.jp\/?p=10235"},"modified":"2023-06-28T19:39:13","modified_gmt":"2023-06-28T10:39:13","slug":"hl7-graph-walk-and-cardinality","status":"publish","type":"post","link":"https:\/\/www.sambuichi.jp\/?p=10235","title":{"rendered":"HL7 Graph Walk and Cardinality"},"content":{"rendered":"<p>Views: 14<\/p><div id=\"header\">\n<h1>HL7 Graph Walk and Cardinality<\/h1>\n<div id=\"toc\" class=\"toc2\">\n<div id=\"toctitle\">Table of Contents<\/div>\n<ul class=\"sectlevel1\">\n<li><a href=\"#_do_we_care_cardinality_then\">1. Do we care cardinality then?<\/a><\/li>\n<li><a href=\"#_how_cardinality_affect_graph_walk_defined_in_hl7\">2. How cardinality affect graph walk defined in HL7?<\/a><\/li>\n<li><a href=\"#_summarize_hl7_graph_walk_using_lifo_queue_and_cardinality\">3. summarize HL7 graph walk using LIFO queue and cardinality.<\/a><\/li>\n<li><a href=\"#_can_you_write_python_program_perform_graph_walk\">4. can you write python program perform graph walk?<\/a><\/li>\n<li><a href=\"#_can_you_handle_following_graph\">5. Can you handle following graph?<\/a><\/li>\n<li><a href=\"#_python_program_perform_hl7_graph_walk\">6. Python program perform HL7 Graph walk<\/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 data-line-7\">\n<p>Nobuyuki SAMBUICHI<\/p>\n<\/div>\n<div class=\"paragraph data-line-9\">\n<p><a href=\"https:\/\/www.iso.org\/committee\/5648297.html\" data-href=\"https:\/\/www.iso.org\/committee\/5648297.html\">ISO\/TC295 Audit data services<\/a>\/SG1 Semantic model Convener<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1 data-line-11\">\n<h2 id=\"_do_we_care_cardinality_then\">1. Do we care cardinality then?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph data-line-14\">\n<div class=\"title\">ChatGPT<\/div>\n<p>Yes, cardinality is an important aspect when designing and modeling associations between entities in a system. It defines the number of instances or elements that can be associated with each other. Cardinality provides information about the relationship between entities and helps determine the multiplicity of the association.<\/p>\n<\/div>\n<div class=\"paragraph data-line-16\">\n<p>Cardinality helps answer questions such as:<\/p>\n<\/div>\n<div class=\"paragraph data-line-18\">\n<p>How many instances of one entity can be associated with another entity?<br \/>\nIs the association one-to-one, one-to-many, or many-to-many?<br \/>\nAre there any constraints or limitations on the number of associations?<br \/>\nUnderstanding the cardinality of associations is crucial for accurately representing the relationships between entities and ensuring the integrity and consistency of the system&#8217;s data model. It helps in determining the structure of the system, defining navigation paths, and validating data constraints.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1 data-line-23\">\n<h2 id=\"_how_cardinality_affect_graph_walk_defined_in_hl7\">2. How cardinality affect graph walk defined in HL7?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph data-line-26\">\n<div class=\"title\">ChatGPT<\/div>\n<p>In HL7, graph walk refers to the process of traversing through a message structure or data model to access specific data elements or relationships. Cardinality plays a significant role in graph walk as it determines the number of instances or repetitions of an element within the message or data model.<\/p>\n<\/div>\n<div class=\"paragraph data-line-28\">\n<p>Cardinality affects graph walk in the following ways:<\/p>\n<\/div>\n<div class=\"paragraph data-line-30\">\n<p>Navigation: Cardinality helps in navigating through the message structure by indicating the number of occurrences of a particular element. It provides information on whether an element is optional (0 or 1 occurrence) or repeatable (multiple occurrences).<\/p>\n<\/div>\n<div class=\"paragraph data-line-32\">\n<p>Iteration: When cardinality allows for multiple occurrences of an element, graph walk may involve iterating or looping through the available instances to access and process the desired data.<\/p>\n<\/div>\n<div class=\"paragraph data-line-34\">\n<p>Data Extraction: Cardinality defines the availability and expected number of occurrences of specific data elements. During graph walk, the cardinality helps determine if the required data element is present and accessible within the message. It also guides in handling scenarios where multiple occurrences of an element are expected, such as retrieving a list of values.<\/p>\n<\/div>\n<div class=\"paragraph data-line-36\">\n<p>Validation: Cardinality is used to validate the conformance of a message against the defined data model. It ensures that the actual occurrence of elements matches the expected cardinality, helping to identify data integrity issues or missing data.<\/p>\n<\/div>\n<div class=\"paragraph data-line-38\">\n<p>In summary, cardinality influences the graph walk process by guiding navigation, iteration, data extraction, and validation of HL7 messages or data models. It provides essential information for effectively accessing and interpreting the data within the message structure.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1 data-line-40\">\n<h2 id=\"_summarize_hl7_graph_walk_using_lifo_queue_and_cardinality\">3. summarize HL7 graph walk using LIFO queue and cardinality.<\/h2>\n<div class=\"sectionbody\">\n<div class=\"quoteblock data-line-43\">\n<blockquote>\n<div class=\"paragraph data-line-45\">\n<p><strong>10.3.3.1.2 Build the Hierarchical Message Definition<\/strong><br \/>\nThis part of building an HMD is really a pair of steps based on the \u201ccurrently selected class.\u201d Initially, the root class is selected. The steps are:<\/p>\n<\/div>\n<div class=\"paragraph data-line-48\">\n<p>Step 1: Copy a class from the Refined Message Information Model to the Hierarchical Message Definition.<\/p>\n<\/div>\n<div class=\"paragraph data-line-50\">\n<p>Step 2: Select another class that is related to the currently selected class through a relationship.<\/p>\n<\/div>\n<div class=\"paragraph data-line-52\">\n<p>As the Technical Committee repeats these steps, it will \u201cwalk\u201d from class to class of the Refined Message Information Model, making its steps along the lines that represent associations. In order to keep its bearings it will maintain a list of the classes that have been selected. As it takes a step to a new class it will add the class name to the list. At certain times, as instructed in the steps below, it will remove the most recent item on the list. This kind of list is often called a LIFO list (for an accounting method for dealing with inventory, last-in, first-out.) It is also called a pushdown stack, a metaphoric reference to the spring-loaded plate carriers used in institutional dining halls, where the new plates added to the top of the stack push down the earlier plates, so the newest plate is taken off the stack first.<\/p>\n<\/div>\n<div class=\"paragraph data-line-54\">\n<p><strong>Step 1: Copy a class to the HMD and the LIFO.<\/strong><\/p>\n<\/div>\n<div class=\"olist upperalpha data-line-56\">\n<ol class=\"upperalpha\" type=\"A\">\n<li class=\"data-line-56\">\n<p>Copy the class to the HMD. Include all attributes and associations that will or may appear in the message. Conventionally, attributes should be placed before the associations, but this is not a requirement.<\/p>\n<\/li>\n<li class=\"data-line-57\">\n<p>Place the selected class on the top of the LIFO list.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<div class=\"paragraph data-line-59\">\n<p><strong>Step 2: Find the next class.<\/strong><\/p>\n<\/div>\n<div class=\"paragraph data-line-61\">\n<p>The following rules provide guidance regarding the choice of the association to use to step from the current class to the next in the \u201cwalk.\u201d Once an association has been used to step from the current class to a new class, do not re-use it unless the current class itself has been reached again by a different association. All selections of associations must be consistent with the intended semantics of the message. This is an important judgment that is made using domain experience and common sense.<\/p>\n<\/div>\n<div class=\"paragraph data-line-63\">\n<p>The following rules must be applied in the order they are listed. As soon one of them is reached that is applicable, select the class it specifies and return to step 1, above.<\/p>\n<\/div>\n<div class=\"olist upperalpha data-line-65\">\n<ol class=\"upperalpha\" type=\"A\">\n<li class=\"data-line-65\">\n<p>Gen-to-Spec. If the current class is a generalization, and if it at least one of its specializations contains information that will be in the message format, or is on a path of associations toward a class that contains such information, then choose the specialized class.<\/p>\n<\/li>\n<li class=\"data-line-66\">\n<p>Intimate Mandatory, Singular. If a (1,1) association from the current class is navigable to a class that seems to add information about the current class, then use it next.<\/p>\n<\/li>\n<li class=\"data-line-67\">\n<p>Other Mandatory, Singular. Pick any (1,1) association that is navigable to needed information.<\/p>\n<\/li>\n<li class=\"data-line-68\">\n<p>Singular. Pick any navigable association that is (0,1) and leads to needed information.<\/p>\n<\/li>\n<li class=\"data-line-69\">\n<p>Other. Pick any navigable association that leads to needed information.<\/p>\n<\/li>\n<li class=\"data-line-70\">\n<p>None. If none of the above rules apply, cross the current class off the LIFO list. Take the prior class on the LIFO as the \u201ccurrent\u201d class and immediately repeat steps A-G. If you have crossed the last class of the LIFO list, you have finished the process of selecting the classes and associations for the Hierarchical Message Definition.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<div class=\"paragraph data-line-72\">\n<p>The sequence of Rules &#169; \u2013 (F) leads to message types that seem more coherent to people. If there is doubt or disagreement about which association to pick based on this rule, the committee may ignore rules &#169; \u2013 (F) completely and pick any association. The message will have the same information content.<\/p>\n<\/div>\n<\/blockquote>\n<div class=\"attribution\">\n&#8212; ISO\/IEC 11179-3 Information technology \u2014 Metadata registries (MDR) \u2014 Part 3 Metamodel for registry common facilities\n<\/div>\n<\/div>\n<div class=\"paragraph data-line-76\">\n<div class=\"title\">ChatGPT<\/div>\n<p>The process of building a Hierarchical Message Definition (HMD) in HL7 involves navigating through the Refined Message Information Model using a LIFO (Last-In, First-Out) list. The LIFO list keeps track of the selected classes during the navigation. Here&#8217;s a summary of the process:<\/p>\n<\/div>\n<div class=\"paragraph data-line-78\">\n<p>Step 1: Copy a class to the HMD and the LIFO list.<\/p>\n<\/div>\n<div class=\"paragraph data-line-80\">\n<p>Copy the class to the HMD, including all attributes and associations that will or may appear in the message.<br \/>\nPlace the selected class on the top of the LIFO list.<\/p>\n<\/div>\n<div class=\"paragraph data-line-83\">\n<p>Step 2: Find the next class.<\/p>\n<\/div>\n<div class=\"paragraph data-line-85\">\n<p>Apply the following rules in order until one of them is applicable:<\/p>\n<\/div>\n<div class=\"paragraph data-line-87\">\n<p>Gen-to-Spec: If the current class is a generalization and its specializations contain information relevant to the message, choose the specialized class.<\/p>\n<\/div>\n<div class=\"paragraph data-line-89\">\n<p>Intimate Mandatory, Singular: If there is a (1,1) association from the current class that adds information about the current class, use it next.<\/p>\n<\/div>\n<div class=\"paragraph data-line-91\">\n<p>Other Mandatory, Singular: Choose any (1,1) association that leads to needed information.<\/p>\n<\/div>\n<div class=\"paragraph data-line-93\">\n<p>Singular: Select any navigable association that is (0,1) and leads to needed information.<\/p>\n<\/div>\n<div class=\"paragraph data-line-95\">\n<p>Other: Choose any navigable association that leads to needed information.<\/p>\n<\/div>\n<div class=\"paragraph data-line-97\">\n<p>None: If none of the above rules apply, cross off the current class from the LIFO list and consider the prior class as the new &#8220;current&#8221; class. Repeat steps A-G.<\/p>\n<\/div>\n<div class=\"paragraph data-line-99\">\n<p>If all classes in the LIFO list have been crossed off, the process of selecting classes and associations for the HMD is finished.<\/p>\n<\/div>\n<div class=\"paragraph data-line-101\">\n<p>Note: Rules C-F (Other Mandatory, Singular; Singular; Other) are intended to create more coherent message types. However, if there is doubt or disagreement about which association to choose based on these rules, they can be ignored, and any association can be picked. The information content of the message will remain the same.<\/p>\n<\/div>\n<div class=\"paragraph data-line-103\">\n<p>By following this process, the HMD can be constructed systematically by traversing the Refined Message Information Model using a LIFO list and selecting appropriate classes and associations based on the defined rules.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1 data-line-105\">\n<h2 id=\"_can_you_write_python_program_perform_graph_walk\">4. can you write python program perform graph walk?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph data-line-107\">\n<div class=\"title\">ChatGPT<\/div>\n<p>Certainly! Here&#8217;s an example of a Python program that performs a graph walk using a LIFO queue:<\/p>\n<\/div>\n<div class=\"listingblock data-line-110\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">from collections import deque\r\n\r\ndef graph_walk(graph, start_node):\r\n    visited = set()\r\n    stack = deque()\r\n    stack.append(start_node)\r\n\r\n    while stack:\r\n        current_node = stack.pop()\r\n        if current_node not in visited:\r\n            visited.add(current_node)\r\n            # Process current node\r\n            print(\"Visiting node:\", current_node)\r\n\r\n            # Add unvisited neighbors to the stack\r\n            neighbors = graph[current_node]\r\n            for neighbor in neighbors:\r\n                if neighbor not in visited:\r\n                    stack.append(neighbor)\r\n\r\n# Example graph represented as an adjacency list\r\ngraph = {\r\n    'A': ['B', 'C'],\r\n    'B': ['D'],\r\n    'C': ['E'],\r\n    'D': [],\r\n    'E': ['F'],\r\n    'F': []\r\n}\r\n\r\n# Starting node for the graph walk\r\nstart_node = 'A'\r\n\r\n# Perform graph walk\r\ngraph_walk(graph, start_node)<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph data-line-148\">\n<p>In this example, we have a graph represented as an adjacency list. The graph_walk function performs the graph walk using a LIFO queue implemented as a deque. It starts from a specified starting node and visits each node in the graph, printing its value.<\/p>\n<\/div>\n<div class=\"paragraph data-line-150\">\n<p>You can modify the code to fit your specific graph structure and customize the processing logic inside the while loop according to your requirements.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1 data-line-152\">\n<h2 id=\"_can_you_handle_following_graph\">5. Can you handle following graph?<\/h2>\n<div class=\"sectionbody\">\n<div class=\"listingblock data-line-155\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">graph = {\r\n  { 'name':'A',\r\n    'association': [\r\n      { 'name':'B',\r\n        'cardinality':'0..1'\r\n      },\r\n      { 'name':'C',\r\n        'cardinality':'1..*'\r\n      }\r\n    ]\r\n  },\r\n  { 'name':'B',\r\n    'association': [\r\n      { 'name':'D',\r\n        'cardinality':'1..1'\r\n      }\r\n    ]\r\n  },\r\n  { 'name':'C',\r\n    'association': [\r\n      { 'name':'E',\r\n        'cardinality':'1..1'\r\n      }\r\n    ]\r\n  },\r\n  { 'name':'D',\r\n    'association': [ ]\r\n  },\r\n  { 'name':'E',\r\n    'association': [\r\n      { 'name':'F',\r\n        'cardinality':'1..1'\r\n      }\r\n    ]\r\n  },\r\n  { 'name':'F',\r\n    'association': [ ]\r\n  }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph data-line-198\">\n<div class=\"title\">ChatGPT<\/div>\n<p>Certainly! Here&#8217;s an updated version of the Python program that handles the provided graph:<\/p>\n<\/div>\n<div class=\"paragraph data-line-201\">\n<div class=\"title\">Note<\/div>\n<p>The code provided by ChatGPT is problematic and after several attempts the code looks like this:<\/p>\n<\/div>\n<div class=\"listingblock data-line-0\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def dfs(graph, start_node, visited=None):\r\n    if visited is None:\r\n        visited = set()\r\n\r\n    visited.add(start_node['name'])\r\n    print(\"Visiting node:\", start_node['name'])\r\n\r\n    for neighbor in start_node['association']:\r\n        if neighbor['name'] not in visited:\r\n            dfs(graph, find_node(graph, neighbor['name']), visited)\r\n\r\ndef find_node(graph, node_name):\r\n    for node in graph:\r\n        if node['name'] == node_name:\r\n            return node\r\n    return None\r\n\r\n# Example graph represented as a list of dictionaries\r\ngraph = [\r\n    { 'name':'A',\r\n      'association': [\r\n          { 'name':'B',\r\n            'cardinality':'0..1'\r\n          },\r\n          { 'name':'C',\r\n            'cardinality':'1..*'\r\n          }\r\n      ]\r\n    },\r\n    { 'name':'B',\r\n      'association': [\r\n          { 'name':'D',\r\n            'cardinality':'1..1'\r\n          }\r\n      ]\r\n    },\r\n    { 'name':'C',\r\n      'association': [\r\n          { 'name':'E',\r\n            'cardinality':'1..1'\r\n          }\r\n      ]\r\n    },\r\n    { 'name':'D',\r\n      'association': [ ]\r\n    },\r\n    { 'name':'E',\r\n      'association': [\r\n          { 'name':'F',\r\n            'cardinality':'1..1'\r\n          }\r\n      ]\r\n    },\r\n    { 'name':'F',\r\n      'association': [ ]\r\n    }\r\n]\r\n\r\n# Starting node for the graph walk\r\nstart_node = find_node(graph, 'A')\r\n\r\n# Perform graph walk using Depth-First Search (DFS)\r\ndfs(graph, start_node)<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph data-line-208\">\n<p>This code results:<\/p>\n<\/div>\n<div class=\"listingblock data-line-210\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-txt\" data-lang=\"txt\">Visiting node: A\r\nVisiting node: B\r\nVisiting node: D\r\nVisiting node: C\r\nVisiting node: E\r\nVisiting node: F<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1 data-line-219\">\n<h2 id=\"_python_program_perform_hl7_graph_walk\">6. Python program perform HL7 Graph walk<\/h2>\n<div class=\"sectionbody\">\n<div class=\"listingblock data-line-0\">\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# generate Audit Data Collection Hierarchy data model from Semantic model CSV\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 os\r\nimport csv\r\n\r\nDEBUG = True\r\nVERBOSE = True\r\nSEP = os.sep\r\n\r\nbase = '.\/semantic\/'\r\nobject_class_file = 'RIM.csv' # Added line item details\r\nhierarchy_file = 'hierarchy.csv'\r\n\r\nselectd_class = ['GL Header']\r\n\r\nLIFOlist = []\r\nhierarchicalModel = []\r\n\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\ndef parseClass(classTerm):\r\n    #Step 1: Copy a class to the hierarchical logical data model and place it on the top of \r\n    # the LIFO list.\r\n    LIFOlist.append(classTerm)\r\n    if DEBUG: print(f'- parseClass({classTerm} {LIFOlist})')\r\n    classObject = objectClassDict[classTerm]\r\n    attributes = classObject['attributes']\r\n    hierarchicalModel.append({'level':len(LIFOlist),'data':classObject})\r\n    # A. Copy the class to the hierarchical logical data model. \r\n    # Copy all properties and associations to the hierarchical logical data model. \r\n    # Conventionally, properties not related to the associated object class should be placed \r\n    # before them,\r\n    # but this is not a requirement.\r\n    for id,attr in attributes.items():\r\n        if len(id)&gt;0 and 'AS'!=attr['bie'][:2]:\r\n            hierarchicalModel.append({'level':1+len(LIFOlist),'data':attr})\r\n    # B. Place the selected class on the top of the LIFO list.\r\n    # Step 2: Find the next class.\r\n    # The following rules provide guidance on choosing the association, \r\n    # which is a property that has the associated object class defined, \r\n    # to use for stepping from the current class to the next in a \"walk\". \r\n    # Once an association has been used to step from the current class to a new class, \r\n    # do not re-use it unless the current class itself has been reached again by a different\r\n    # association. \r\n    # All selections of associations must be consistent with the intended semantics of the\r\n    # data.\r\n    # The following rules should be applied in the order they are listed.\r\n    # As soon one of them is reached that is applicable, select the class it specifies and \r\n    # return to step 1, above.\r\n    # A. Gen-to-Spec. \r\n    # If the current class is a generalization, \r\n    # and if it at least one of its specializations contains information that will be in the\r\n    # message format or is on a path of associations toward a class that contains such \r\n    # information, then choose the specialized class.\r\n    if 'SP'==classObject['bie'][:2]:\r\n        selectedClassTerm = classObject['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            parseClass(selectedClassTerm)\r\n    specialClasses = [cls for cls in attributes.values() if 'SP'==cls['bie'][:2]]\r\n    for attr in specialClasses:\r\n        selectedClassTerm = attr['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            parseClass(selectedClassTerm)\r\n    # #\r\n    # if 'AS'==classObject['bie'][:2]:\r\n    #     hierarchicalModel.append({'level':1+len(LIFOlist),'data':classObject})\r\n    # B. Intimate Mandatory, Singular. \r\n    # If a (1,1) association from the current class is navigable to a class that seems to\r\n    # add information about the current class, then use it next.\r\n    # C. Other Mandatory, Singular. \r\n    # Pick any (1,1) association that is navigable to needed information.\r\n    if 'AS'==classObject['bie'][:2] and '1..1'==classObject['card']:\r\n        selectedClassTerm = classObject['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            parseClass(selectedClassTerm)\r\n    mandateClasses = [cls for cls in attributes.values()\r\n                        if 'AS'==cls['bie'][:2] and '1..1'==cls['card']]\r\n    for attr in mandateClasses:\r\n        selectedClassTerm = attr['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            hierarchicalModel.append({'level':1+len(LIFOlist),'data':attr})\r\n            parseClass(selectedClassTerm)\r\n    # D. Singular. \r\n    # Pick any navigable association that is (0,1) and leads to needed information.\r\n    if 'AS'==classObject['bie'][:2] and '0..1'==classObject['card']:\r\n        selectedClassTerm = classObject['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            hierarchicalModel.append({'level':1+len(LIFOlist),'data':attr})\r\n            parseClass(selectedClassTerm)\r\n    singularClasses = [cls for cls in attributes.values() \r\n                        if 'AS'==cls['bie'][:2] and '0..1'==cls['card']]\r\n    for attr in singularClasses:\r\n        selectedClassTerm = attr['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            hierarchicalModel.append({'level':1+len(LIFOlist),'data':attr})\r\n            parseClass(selectedClassTerm)\r\n    # E. Other. \r\n    # Pick any navigable association that leads to needed information.\r\n    if 'AS'==classObject['bie'][:2] and '..*'==classObject['card'][1:]:\r\n        selectedClassTerm = classObject['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            parseClass(selectedClassTerm)\r\n    otherClasses = [cls for cls in attributes.values() \r\n                        if 'AS'==cls['bie'][:2] and '..*'==cls['card'][1:]]\r\n    for attr in otherClasses:\r\n        selectedClassTerm = attr['associatedClass']\r\n        if not selectedClassTerm in LIFOlist:\r\n            hierarchicalModel.append({'level':1+len(LIFOlist),'data':attr})\r\n            parseClass(selectedClassTerm)\r\n    # F. None. If none of the above rules apply, cross the current class off the LIFO list. \r\n    # Take the prior class on the LIFO as the \u201ccurrent\u201d class and immediately repeat steps\r\n    # A-E. \r\n    # If you have crossed the last class of the LIFO list, you have finished the process of\r\n    # selecting the classes and associations for the hierarchical logical data model.\r\n    # The sequence of Rules (C) \u2013 (F) leads to message types that seem more coherent to \r\n    # people. \r\n    # If there is doubt or disagreement about which association to pick based on this rule,\r\n    # the committee may ignore rules (C) \u2013 (F) completely and pick any association. \r\n    # The message will have the same information content.\r\n    LIFOlist.pop(-1)\r\n    if DEBUG: print(f'LIFO list {LIFOlist}')\r\n\r\nif __name__ == '__main__':\r\n    objectClassDict = {}\r\n    entries = {}\r\n    object_class_file = f'{base}{object_class_file}'.replace('\/', SEP)\r\n    object_class_file = file_path(object_class_file)\r\n    header = ['bie','id','level','card','classTerm','propertyTerm','representation','associatedClass']\r\n    with open(object_class_file, encoding='utf_8', newline='') as f:\r\n        reader = csv.DictReader(f, fieldnames=header)\r\n        next(reader)\r\n        attributes = []\r\n        detailsClass = set()\r\n        for row in reader:\r\n            bie = row['bie']\r\n            if ('CC'!=bie[-2:] and 'BIE'!=bie[-3:]) or len(bie)&gt;5:\r\n                continue\r\n            classTerm = row['classTerm'].replace(u'\\xa0', ' ').replace('  ',' ').strip()\r\n            propertyTerm = row['propertyTerm'].replace(u'\\xa0', ' ').replace('  ',' ').strip()\r\n            associatedTerm = row['associatedClass'].replace(u'\\xa0', ' ').replace('  ',' ').strip()\r\n            id = row['id']\r\n            if bie in ['ACC','ABIE','SPCC','SPBIE']:\r\n                if not classTerm in objectClassDict:\r\n                    objectClassDict[classTerm] = row\r\n                    objectClassDict[classTerm]['attributes'] = {}\r\n            else:\r\n                objectClassDict[classTerm]['attributes'][id] = row\r\n                objectClassDict[classTerm]['attributes'][id]['classTerm'] = classTerm\r\n                objectClassDict[classTerm]['attributes'][id]['associatedClass'] = associatedTerm\r\n            if 'AS'==bie[:2] and 'has'==propertyTerm[:3]:\r\n                detailsClass.add(associatedTerm)\r\n\r\n    # selectd_class = objectClassDict.keys()\r\n    for classTerm in selectd_class:\r\n        if classTerm in detailsClass:\r\n            continue\r\n        parseClass(classTerm)\r\n\r\n    hierarchy_records = []\r\n    for entry in hierarchicalModel:\r\n        level = entry['level']\r\n        data = entry['data']\r\n        record = {}\r\n        for key in header:\r\n            record[key] = data[key]\r\n        record['level'] = str(level)\r\n        hierarchy_records.append(record)\r\n\r\n    hierarchy_file = f'{base}{hierarchy_file}'.replace('\/', SEP)\r\n    hierarchy_file = file_path(hierarchy_file)\r\n    with open(hierarchy_file, 'w', encoding='utf_8', newline='') as f:\r\n        writer = csv.DictWriter(f, fieldnames=header)\r\n        writer.writeheader()\r\n        writer.writerows(hierarchy_records)        \r\n\r\n    print(f'** END {hierarchy_file}')<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div id=\"footer\">\n<div id=\"footer-text\">\nLast updated 2023-06-28 19:37:59 +0900\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Views: 14 HL7 Graph Walk and Cardinality Table of Contents 1. Do we care cardinality then? 2. How cardinality  [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":10236,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[71,69,30],"tags":[],"_links":{"self":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/10235"}],"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=10235"}],"version-history":[{"count":2,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/10235\/revisions"}],"predecessor-version":[{"id":10240,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/10235\/revisions\/10240"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/media\/10236"}],"wp:attachment":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10235"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10235"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10235"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}