Select to view content in your preferred language

find text element in MXD with wildcard?

3849
28
Jump to solution
11-13-2018 02:16 PM
JaredPilbeam2
MVP Regular Contributor

I have a working script that searches for a text element in an MXD and replaces it with new text. I'm using it to update the "print date: mo./day/year". But, this method is sort of limited in that it only finds that exact string. In my map document folder, the dates of these maps differ from each other. So, how can I make the script replace an open-ended string? 

I've tried:

oldText = "Print Date: "

and

oldText = "Print Date: *"

As the script is here, "oldText = Print Date: 9.6.2016" will be replaced with "newText = Print Date: 11/13/2018". But, dates on other maps could be anything. If I could replace the old with dynamic text date that would be even better.

arcpy.env.workspace = Workspace = r"path\to\TestFolder"
Output = r"path\to\TestFolder2"
oldText = "Print Date: 9.6.2016"
oldList = oldText.split(', ')
newText = "Print Date: 11/13/2018"
newList = newText.split(', ')

# list the mxds of the workspace folder
for mxdname in arcpy.ListFiles("*.mxd"):
    print "checking document: {}".format(mxdname)
# set the variable
    mxd = arcpy.mapping.MapDocument(Workspace + "\\" + mxdname)
# replace elements that occur in the map document
    for elm in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT"):
        counter = 0
        for text in oldList:
            if text in elm.text:
                elm.text = elm.text.replace(text, newList[counter])
                print '{} changed'.format(elm.text)
                counter = counter + 1
            else:
                counter = counter + 1

    for elm in arcpy.mapping.ListLayoutElements(mxd, ""):
        counter = 0
        for text in oldList:
            if text in mxd.title:
                mxd.title = elm.text.replace(text, newList[counter])
                counter = counter + 1
            else:
                counter = counter + 1
# move the mxd.saveACopy outside of the if loop so a copy is saved even it does not meet the condition of the if loops
    mxd.save() #(os.path.join(Output + "\\" + mxdname))
# do not include this delete statement inside the above loop or it will delete the mxd object inside the loop. Make sure to dedent.
del mxd‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
28 Replies
RandyBurton
MVP Alum

Actually, my previous look was too quick.  At line 13 in your latest code, you are starting to loop through the text elements in your map.  You need to look at the text of each element, that is elm.text.  I suspect that you do not want to compare the text to oldText which doesn't change - then every text element would be changed.  You mentioned earlier that you had some variations in the text ('Print Date', 'Print date',  'Plot date', etc.).  You may want to just use the upper case 'DATE' for comparison, possibly with a space ' DATE' if one will always be there.

    for elm in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT"):
        if "PRINT DATE" in elm.text.upper(): #check text in elm
            elm.text = newdate # change to dynamic date
            # if you want to name the text box as 'PrintDate'
            elm.name = 'PrintDate' 
            print "+++date changed+++"‍‍‍‍‍‍‍‍‍‍‍

Hope this helps.

JaredPilbeam2
MVP Regular Contributor

Randy,

Thanks, these did work but they replaced everything in the text box with "Print date: 11/28/2018".  

newdate = "Print date: <dyn type=\"date\" format=\"\"/>"

        if " DATE" in elm.text.upper():
            elm.text = newdate
        if "PRINT DATE" in elm.text.upper():
            elm.text = newdate
0 Kudos
RandyBurton
MVP Alum

these did work but they replaced everything in the text box with "Print date: 11/28/2018"

The map will display today's date using the dynamic text format, however if you look at the properties of the text box, you should see the newdate formula ( Print date: <dyn type="date" format=""/> ) as the text value.  Is this not the case?

dynamic date

0 Kudos
JaredPilbeam2
MVP Regular Contributor

I also just tried name the text box, and then changing the text to the "newdate". But this changed the whole text box too.

    for elm in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT"):
        if "PRINT DATE" in elm.text.upper():
            elm.name = 'PrintDate'
            if  elm.name == 'PrintDate': #the name of the text element
                elm.text = newdate
                print "+++date changed+++"‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

from this:


to this:

"Print date: 11/28/2018"

Almost there, but I'm trying to avoid changing the rest of the text in the text box!

EDIT: Yes, to answer your latest post, it did exactly what you're pointing out. The problem is that the rest of the text in that same box is gone after the change.

0 Kudos
RandyBurton
MVP Alum

There are a couple of ways that you can go.  If all the date text contains the address info, you could replace the entire contents with the similar contents that include dynamic text for the date.

If the print date line is separated by new line codes \n, you can split your old text, replace the part with the print date and rejoin the text.  It appears that your text might follow this pattern.  If so, you can try something like this:

import arcpy, glob, os

path = r"C:\Directory\with\mxds"

os.chdir(path)
for file in glob.glob("*.mxd"):
    print "Processing: {}".format(file)

    mxd = arcpy.mapping.MapDocument(file)
    
    for elm in arcpy.mapping.ListLayoutElements(mxd,"TEXT_ELEMENT"):
        if ' DATE' in elm.text.upper():
            txt = elm.text.split('\n')
            for i, t in enumerate(txt):
                if ' DATE' in t.upper():
                    # txt = "Print date: <dyn type=\"date\" format=\"\"/>"
                    # format date with periods, no leading zero in month
                    txt[i] = "Print date: <dyn type=\"date\" format=\"M.dd.yyyy\"/>"
            elm.text = '\n'.join(txt)
            elm.name = 'DateBox'
        print elm.text, elm.name

    mxd.save()
    del mxd‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

If the date text that you want replaced is on the same line with other text ( such as:  Print Date: 11/28/2018  By: JP ) then you may need to consider an alternative like regular expressions if a pattern in the text cannot be found.   There is a discussion on stackoverflow ( Extracting date from a string in Python ) that would be of interest if you need another option.

JaredPilbeam2
MVP Regular Contributor

Randy,

Thanks for that. I have actually attempted to just replace the whole text box with text including the new dynamic date. It worked, but the text was really hard to read. And using your latest script it's doing the same thing:

0 Kudos
RandyBurton
MVP Alum

When you look at the text box's properties, are there changes to the font, font size or centering?

0 Kudos
JaredPilbeam2
MVP Regular Contributor

Here's the properties of the text box above. The address line is not where it should be. So, in the script I put another \n after the dynamic date (see below). That didn't change anything.

    for elm in arcpy.mapping.ListLayoutElements(mxd,"TEXT_ELEMENT"):
        if ' DATE' in elm.text.upper():
            txt = elm.text.split("\n")
            for i, t in enumerate(txt):
                if ' DATE' in t.upper():
                    txt[i] = "Print date: <dyn type=\"date\" format=\"\"/>\n"
##                    format date with periods, no leading zero in month
##                    txt = "Print date: <dyn type=\"date\" format=\"M.dd.yyyy\"/>"
            elm.text = '\n'.join(txt)
            elm.name = 'DateBox'
        print elm.text, elm.name
0 Kudos
RandyBurton
MVP Alum

You are on the right track to add the new line character in the print date line of your code.  It appears that other new lines are missing in the text block which is probably why things are a bit jumbled when displayed.  You can do a couple of things:  compose the text as a long line with newlines included (see line 9 below)  or join shorter lines together with the new line character (lines 1-7).  Hope this helps.

>>> txtBlock = [
    'U.S. House of Representatives',
    'Prepared by the Will County GIS Division',
    'Print date: <dyn type=\"date\" format=\"\"/>',
    '302 N. Chicago St. Joliet, Il 60432'
    ]
>>> newTxt = "\n".join(txtBlock)
>>> newTxt
'U.S. House of Representatives\nPrepared by the Will County GIS Division\nPrint date: <dyn type="date" format=""/>\n302 N. Chicago St. Joliet, Il 60432'
>>> print newTxt
U.S. House of Representatives
Prepared by the Will County GIS Division
Print date: <dyn type="date" format=""/>
302 N. Chicago St. Joliet, Il 60432
>>> 
JaredPilbeam2
MVP Regular Contributor

That should work, but neither do? The text is still jumbled in the map document text box. Strange. I then tried on a text box with similar text in a new map document and it worked fine. I'd hate to think the text boxes in these old map documents are corrupt, or something. 

0 Kudos