## Technical Documentation: Parsing TIA Portal `_XRef.xml` Files for Call Tree Generation **Version:** 1.0 **Date:** 2025-05-05 ### 1. Introduction This document describes the structure and interpretation of the XML files (`*_XRef.xml`) generated by the TIA Portal Openness `export_cross_references` function (available via libraries like `siemens_tia_scripting`). The primary goal is to enable software developers to programmatically parse these files to extract block call relationships and build a comprehensive call tree for a PLC program. The `_XRef.xml` file contains detailed information about all objects referenced _by_ a specific source object (e.g., an OB, FB, or FC). By processing these files for all relevant blocks, a complete picture of the program's call structure can be assembled. ### 2. File Format Overview The `_XRef.xml` file is a standard XML document. Its high-level structure typically looks like this: XML ```xml ...
...
... ... ... ... ...
...
... ... ... ... ...
...
... ... Uses
``` ### 3. Key XML Elements for Call Tree Construction To build a call tree, you need to identify the _caller_ and the _callee_ for each block call. The following XML elements are essential: 1. **``:** Represents the block performing the calls (the **caller**). - **``:** The symbolic name of the caller block (e.g., `_CYCL_EXC`). - **`
`:** The absolute address (e.g., `%OB1`). - **``:** The type of the caller block (e.g., `LAD-Organization block`). 2. **``:** Represents an object being referenced by the `SourceObject`. This _could_ be the **callee**. - **``:** The symbolic name of the referenced object (e.g., `BlenderCtrl__Main`, `Co2_Counters_DB`). - **`
`:** The absolute address (e.g., `%FC2000`, `%DB1021`). - **``:** The type of the referenced object (e.g., `LAD-Function`, `Instance DB of Co2_Counters [FB1020]`). This is vital for identifying FCs and FBs (via their instance DBs). 3. **``:** Specifies exactly how and where the `ReferenceObject` is used within the `SourceObject`. - **``:** **This is the most critical element for call trees.** Look for the value `Call`. This indicates a direct Function Call (FC). An access type of `InstanceDB` indicates the usage of an instance DB, which implies a Function Block (FB) call is occurring. - **``:** Provides human-readable context about where the reference occurs within the caller's code (e.g., `@_CYCL_EXC ▶ NW3 (Blender CTRL)`). Useful for debugging or visualization. ### 4. Data Extraction Strategy for Call Tree A program parsing these files should follow these steps for each `_XRef.xml` file: 1. **Parse XML:** Load the `_XRef.xml` file using a suitable XML parsing library (e.g., Python's `xml.etree.ElementTree` or `lxml`). 2. **Identify Caller:** Navigate to the `` element and extract its ``. This is the caller block for all references within this file. 3. **Iterate References:** Loop through each `` within the `` section of the ``. 4. **Iterate Locations:** For each ``, loop through its `` elements. 5. **Filter for Calls:** Check the text content of the `` tag within each ``. - **If `Access` is `Call`:** - The `` of the current `` is the **callee** (an FC). - Record the relationship: `Caller Name` -> `Callee Name (FC)`. - **If `Access` is `InstanceDB`:** - This signifies an FB call is happening using this instance DB. - The `` of the current `` is the Instance DB name (e.g., `Co2_Counters_DB`). - To find the actual FB being called, examine the `` of this `ReferenceObject`. It usually contains the FB name/number (e.g., `Instance DB of Co2_Counters [FB1020]`). Extract the FB name (`Co2_Counters`) or number (`FB1020`). This is the **callee**. - Record the relationship: `Caller Name` -> `Callee Name (FB)`. 6. **Store Relationships:** Store the identified caller-callee pairs in a suitable data structure. ### 5. Building the Call Tree Data Structure After parsing one or more `_XRef.xml` files, the extracted relationships can be stored. Common approaches include: - **Dictionary (Adjacency List):** A dictionary where keys are caller names and values are lists of callee names. Python ```python call_tree = { '_CYCL_EXC': ['BlenderCtrl__Main', 'MessageScroll', 'ITC_MainRoutine', 'Co2_Counters', 'ProcedureProdBrixRecovery', 'Key Read & Write', 'GNS_PLCdia_MainRoutine'], 'BlenderCtrl__Main': ['SomeOtherBlock', ...], # ... other callers } ``` - **Graph Representation:** Using libraries like `networkx` in Python to create a directed graph where blocks are nodes and calls are edges. This allows for more complex analysis (e.g., finding paths, cycles). - **Custom Objects:** Define `Block` and `Call` classes for a more object-oriented representation. ### 6. Handling Multiple Files A single `_XRef.xml` file only details the references _from_ one `SourceObject`. To build a complete call tree for the entire program or PLC: 1. **Export References:** Use the Openness script to call `export_cross_references` for _all_ relevant OBs, FBs, and FCs in the project. 2. **Process All Files:** Run the parsing logic described above on each generated `_XRef.xml` file. 3. **Aggregate Results:** Combine the caller-callee relationships extracted from all files into a single data structure (e.g., merge dictionaries or add nodes/edges to the graph). ### 7. Example (Conceptual Python using `xml.etree.ElementTree`) Python ```python import xml.etree.ElementTree as ET import re # For extracting FB name from TypeName def parse_xref_for_calls(xml_file_path): """Parses a _XRef.xml file and extracts call relationships.""" calls = {} # {caller: [callee1, callee2, ...]} try: tree = ET.parse(xml_file_path) root = tree.getroot() # Namespace handling might be needed depending on the xmlns ns = {'ns0': 'TestNamespace1'} # Adjust namespace if different in your file for source_object in root.findall('.//ns0:SourceObject', ns): caller_name = source_object.findtext('ns0:Name', default='UnknownCaller', namespaces=ns) if caller_name not in calls: calls[caller_name] = [] for ref_object in source_object.findall('.//ns0:ReferenceObject', ns): ref_name = ref_object.findtext('ns0:Name', default='UnknownRef', namespaces=ns) ref_type_name = ref_object.findtext('ns0:TypeName', default='', namespaces=ns) for location in ref_object.findall('.//ns0:Location', ns): access_type = location.findtext('ns0:Access', default='', namespaces=ns) if access_type == 'Call': # Direct FC call if ref_name not in calls[caller_name]: calls[caller_name].append(ref_name) elif access_type == 'InstanceDB': # FB call via Instance DB # Extract FB name/number from TypeName (e.g., "Instance DB of BlockName [FB123]") match = re.search(r'Instance DB of (.*?) \[([A-Za-z]+[0-9]+)\]', ref_type_name) callee_fb_name = 'UnknownFB' if match: # Prefer symbolic name if available, else use number callee_fb_name = match.group(1) if match.group(1) else match.group(2) elif 'Instance DB of' in ref_type_name: # Fallback if regex fails callee_fb_name = ref_type_name.split('Instance DB of ')[-1].strip() if callee_fb_name not in calls[caller_name]: calls[caller_name].append(callee_fb_name) except ET.ParseError as e: print(f"Error parsing XML file {xml_file_path}: {e}") except FileNotFoundError: print(f"Error: File not found {xml_file_path}") # Clean up entries with no calls calls = {k: v for k, v in calls.items() if v} return calls # --- Aggregation Example --- # all_calls = {} # for xref_file in list_of_all_xref_files: # file_calls = parse_xref_for_calls(xref_file) # for caller, callees in file_calls.items(): # if caller not in all_calls: # all_calls[caller] = [] # for callee in callees: # if callee not in all_calls[caller]: # all_calls[caller].append(callee) # print(all_calls) ``` _Note: Namespace handling (`ns=...`) in ElementTree might need adjustment based on the exact default namespace declared in your XML files._ ### 8. Considerations - **Function Block Calls:** Remember that FB calls are identified indirectly via the `InstanceDB` access type and parsing the `` of the `ReferenceObject`. - **System Blocks (SFC/SFB):** Calls to system functions/blocks should appear similarly to FC/FB calls and can be included in the tree. Their `` might indicate they are system blocks. - **TIA Portal Versions:** While the basic structure is consistent, minor variations in tags or namespaces might exist between different TIA Portal versions. Always test with exports from your specific version. - **Data References:** This documentation focuses on the call tree. The XML also contains `Read`, `Write`, `RW` access types, which can be parsed similarly to build a full cross-reference map for tags and data blocks. ### 9. Conclusion The `_XRef.xml` files provide a detailed, machine-readable description of block references within a TIA Portal project. By parsing the XML structure, focusing on the ``, ``, and specifically the `` tag within ``, developers can reliably extract block call information and construct program call trees for analysis, documentation, or visualization purposes. Remember to aggregate data from multiple files for a complete program overview.