Find and replace textnote in multiple projects from a directory

Hi there,
Not sure if someone can help me, but I thought I’d post anyway. I was unable to find a similar topic

Objective:
Open hundreds of projects from a given directory, search for a given value in the text notes and replace it with a new given value. Then of course I need to sync each file and close them.

Problem, I’m not sure how to set the text in the document and then save the document. I believe I need a node to set text in document, unless anyone else knows how I can use the default one.

Thank you in advance, I am pretty green with Dynamo as well

What does the error say?

image any thoughts @Nick_Boyts?

There are transaction nodes available, what happens if you place the node between Start and End?
image

I did a bit more digging into the Dynamo source and I think you may be out of luck…
The TextNote.SetText node uses the following code in C#
TransactionManager.Instance.EnsureInTransaction(Application.Document.Current.InternalDocument); [link]
This is pointing to the InternalDocument which is the accessed via the Dynamo Document Manager from the CurrentUIDocument which you could guess as coming from the User Interface.

Digging even deeper I noticed that Revit provides a Carriage Return (\r) at the end of every line of text so the safest way to update a line of text will be using the str.replace() method in python

Try this code which returns a dictionary of ‘In’ and ‘Out’ TextNotes. Note I haven’t yet tested it on a loaded document, just the current one

import sys
import clr

clr.AddReference("RevitNodes")
import Revit

clr.AddReference("RevitServices")
from RevitServices.Transactions import TransactionManager

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

text_notes = UnwrapElement(IN[0]) if isinstance(IN[0], list) else [UnwrapElement(IN[0])]
get_text = IN[1]  # String to find for updating
set_text = IN[2]  # New string to replace old string

output = {}

if all(IN):
    for tn in text_notes:
        if get_text in tn.Text:
            TransactionManager.Instance.EnsureInTransaction(tn.Document)
            tn.Text = tn.Text.replace(get_text, set_text)
            TransactionManager.Instance.TransactionTaskDone()
            output.setdefault("In", []).append(tn)
        else:
            output.setdefault("Out", []).append(tn)

OUT = output

Thank you @Mike.Buttery for you reply. I am away sick today, so I will give it a try once I am able to get back to my computer. I appreciate you looking into that for me

1 Like

The issue here is that most nodes expect to be run on the active document. In order to modify a specified document, you either need a node that already has that input or you need to write your own code in python.

@Nick_Boyts Thanks for your reply. I kind of thought that was where this was headed. I have already created a similar graph for changing a parameter in multiple projects, but I was able to find a “setParameterByName in Document” node from Genius Loci that allowed it to work. Text notes, don’t seem to fall under a typical parameter which was leading me to this conclusion. Unfortunately for me, writing a python script is not in my skillset at this time. Thanks again!

It’s worth giving a shot. Modifying a text note’s content is actually really straightforward so it would be a good opportunity to start learning.

2 Likes