Replacing a component in a Flowchart

Tips, Tricks and methods for programming, learn ways of making your programming life easier, and share your knowledge with others.
Post Reply
mnfisher
Valued Contributor
Posts: 1608
http://meble-kuchenne.info.pl
Joined: Wed Dec 09, 2020 9:37 pm
Has thanked: 142 times
Been thanked: 756 times

Replacing a component in a Flowchart

Post by mnfisher »

I recently hit upon a situation where I needed to replace one component in a Flowchart with a different one.

This can be done by finding each macro in the component and modifying it by hand.
It can be done by using 'Replace' - but only if the components are compatible (I didn't manage to get this to work - using two displays with Initialise called on one - attempting to change to the other display gave a 'this will lead to errors' message)

Being lazy - I wrote a small Python script to do the hard work :-)

So using (for example) - a Flowchart (Flowcode1.fcfx) with two components - one with handle 'gLCD_SSD1306_i2c1' that I want to replace with gLCD_ST7565R1.

On a command line I do:

python component.py Flowcode1 NewFile gLCD_SSD1306_i2c1 gLCD_ST7565R1

which reads Flowcode1.fcfx and outputs a new file NewFile.fcfx with gLCD_SSD1306_i2c1 replaced by gLCD_ST7565R1 - I can then edit NewFile and delete the unused component. Any compatibility issues (different number of arguments or missing macros) will be highlighted as an error - and can be corrected.

Note that NewFile.fcfx will be overwritten if it already exists (and if you set to be the same as input will overwrite that - but check results first !! )

Code: Select all

import argparse
from bs4 import BeautifulSoup

def replace_component_in_xml(file_path, new_path, old_value, new_value):
    """
    Reads an XML file, finds all <macro> tags where the 'component' attribute
    matches old_value, and replaces it with new_value.

    Args:
        file_path (str): The path to the input XML file.
        new_path (str): Output as new file
        old_value (str): The component value to search for.
        new_value (str): The new value to replace the old_value with.
    """
    try:
        # Step 1: Read the XML file
        with open(file_path, 'r', encoding='utf-8') as file:
            content = file.read()

        # Step 2: Parse the XML with BeautifulSoup
        soup = BeautifulSoup(content, 'xml')

        # Step 3: Find all matching nodes
        nodes_to_update = soup.find_all('command', component=old_value)

        if not nodes_to_update:
            print(f"No <macro> nodes with component='{old_value}' found. No changes made.")
            return

        # Step 4: Iterate and replace the attribute value
        for tag in nodes_to_update:
            original_tag = str(tag)
            tag['component'] = new_value
            print(f"Found and replaced: {original_tag} -> {str(tag)}")

        # Step 5: Write the changes back to the file
        with open(new_path, 'w', encoding='utf-8') as file:
            file.write(str(soup.prettify()))

        print(f"\nSuccessfully updated {len(nodes_to_update)} node(s) in {file_path} - saved as {new_path}.")

    except FileNotFoundError:
        print(f"Error: The file '{file_path}' was not found.")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

def main():
    """
    Sets up command-line argument parsing and calls the main function.
    """
    # Initialize the parser
    parser = argparse.ArgumentParser(
        description="Replaces the 'component' attribute value in <macro> tags of an XML file."
    )

    # Add the arguments we expect
    parser.add_argument("file_path", help="The path to the Flowcode file to process.")
    parser.add_argument("out_path", help="The new file to save Flowchart as")
    parser.add_argument("old_value", help="The current component value to be replaced (e.g., 'abc').")
    parser.add_argument("new_value", help="The new component value to set (e.g., 'Def').")

    # Parse the arguments from the command line
    args = parser.parse_args()

    # Call the main processing function with the parsed arguments
    replace_component_in_xml(args.file_path + ".fcfx", args.out_path + ".fcfx", args.old_value, args.new_value)

if __name__ == "__main__":
    main()
You will need to have python3 installed.
Save the code as 'component.py' (or name.py of your choice)
You will need BeautifulSoup and lxml (pip install bs4 lxml)

Anyone who tries this - please let us know how you get on...

Martin

WingNut
Posts: 269
Joined: Tue Jul 13, 2021 1:53 pm
Has thanked: 40 times
Been thanked: 29 times

Re: Replacing a component in a Flowchart

Post by WingNut »

How many times have I wanted this? Can it be added as feature in flowcode?

MJU20
Posts: 353
Joined: Tue Dec 08, 2020 5:11 pm
Has thanked: 101 times
Been thanked: 70 times

Re: Replacing a component in a Flowchart

Post by MJU20 »

Yes, it should be integrated into FC!
Nice job, mnfisher, glad to know there are more lazy people like me! :)

medelec35
Matrix Staff
Posts: 2051
Joined: Wed Dec 02, 2020 11:07 pm
Has thanked: 638 times
Been thanked: 690 times

Re: Replacing a component in a Flowchart

Post by medelec35 »

WingNut wrote:
Tue Aug 05, 2025 5:29 pm
How many times have I wanted this? Can it be added as feature in flowcode?
Flowcode does already have that feature, see the Flowcode Wiki here

What you do is add the new component you want to swap with, then delete it.
Now you can use the replace option., which is right -click on the component you wish to replace.
If using a script to perform this, you need to take in account that you just can't rename functions, the GUID will also require changing to the GUID of the new component.
Otherwise you will still have the original component renamed
Martin

Post Reply