ParamManagerScripts/backend/script_groups/XML Parser to SCL/xref_info.md

11 KiB

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 version="1.0" encoding="utf-8"?>
<CrossReferences xmlns:i="..." xmlns="...">
  <Sources>
    <SourceObject> <Name>...</Name>
      <Address>...</Address>
      <Device>...</Device>
      <Path>...</Path>
      <TypeName>...</TypeName>
      <UnderlyingObject>...</UnderlyingObject>
      <Children />
      <References> <ReferenceObject> <Name>...</Name>
          <Address>...</Address>
          <Device>...</Device>
          <Path>...</Path>
          <TypeName>...</TypeName> <UnderlyingObject>...</UnderlyingObject>
          <Locations> <Location>
              <Access>...</Access> <Address>...</Address>
              <Name>...</Name>
              <ReferenceLocation>...</ReferenceLocation> <ReferenceType>Uses</ReferenceType>
              </Location>
            </Locations>
        </ReferenceObject>
        </References>
    </SourceObject>
    </Sources>
</CrossReferences>

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. <SourceObject>: Represents the block performing the calls (the caller).

    • <Name>: The symbolic name of the caller block (e.g., _CYCL_EXC).
    • <Address>: The absolute address (e.g., %OB1).
    • <TypeName>: The type of the caller block (e.g., LAD-Organization block).
  2. <ReferenceObject>: Represents an object being referenced by the SourceObject. This could be the callee.

    • <Name>: The symbolic name of the referenced object (e.g., BlenderCtrl__Main, Co2_Counters_DB).
    • <Address>: The absolute address (e.g., %FC2000, %DB1021).
    • <TypeName>: 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. <Location>: Specifies exactly how and where the ReferenceObject is used within the SourceObject.

    • <Access>: 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.
    • <ReferenceLocation>: 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 <SourceObject> element and extract its <Name>. This is the caller block for all references within this file.
  3. Iterate References: Loop through each <ReferenceObject> within the <References> section of the <SourceObject>.
  4. Iterate Locations: For each <ReferenceObject>, loop through its <Location> elements.
  5. Filter for Calls: Check the text content of the <Access> tag within each <Location>.
    • If Access is Call:
      • The <Name> of the current <ReferenceObject> 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 <Name> of the current <ReferenceObject> is the Instance DB name (e.g., Co2_Counters_DB).
      • To find the actual FB being called, examine the <TypeName> 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

    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

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 <TypeName> 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 <TypeName> 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 <SourceObject>, <ReferenceObject>, and specifically the <Access> tag within <Location>, 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.