Hi everyone,
I have created a python script and run it within ArcGIS Pro that takes attribute values from a feature class and populates them into << >> placeholders within a formatted docx template.
I am having issues in ensuring that the domain descriptions are passed through to the <<DIVISION>> placeholder, as right now the script populates the coded value domain rather than the full domain description (i.e. USA instead of United States of America). Is there a way to alter my python script in order to ensure the full description values are being passed through?
import arcpy
import docx
from datetime import datetime
import os
# Define the paths
inputfilename = r"C:\Users\UserName\Desktop\GTATable\FieldSummary_TEMPLATE.docx"
outputfolder = r"C:\Users\UserName\Desktop\Table\GeneratedDocuments"
feature_class = r"C:\Users\UserName\Documents\ArcGIS\Projects\Table\ACCS.gdb\FieldWork"
# Function to replace text in paragraphs and tables
def docx_find_replace_text(doc, old_text, new_text):
for paragraph in doc.paragraphs:
if old_text in paragraph.text:
for run in paragraph.runs:
if old_text in run.text:
run.text = run.text.replace(old_text, new_text)
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
if old_text in paragraph.text:
for run in paragraph.runs:
if old_text in run.text:
run.text = run.text.replace(old_text, new_text)
# Function to replace text in headers
def docx_find_replace_header(doc, old_text, new_text):
"""Replace text in the header, handling complex layouts like tables and fragmented runs."""
for section in doc.sections:
header = section.header
for paragraph in header.paragraphs:
replace_text_in_paragraph(paragraph, old_text, new_text)
for table in header.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
replace_text_in_paragraph(paragraph, old_text, new_text)
# Function to replace text in footers
def docx_find_replace_footer(doc, old_text, new_text):
"""Replace text in the footer, handling placeholders in paragraphs and tables."""
for section in doc.sections:
footer = section.footer
for paragraph in footer.paragraphs:
replace_text_in_paragraph(paragraph, old_text, new_text)
for table in footer.tables:
for row in table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
replace_text_in_paragraph(paragraph, old_text, new_text)
# Function to handle fragmented runs in paragraphs
def replace_text_in_paragraph(paragraph, old_text, new_text):
"""Replace placeholder text in a paragraph, handling fragmented runs."""
full_text = ''.join(run.text for run in paragraph.runs)
if old_text in full_text:
updated_text = full_text.replace(old_text, new_text)
for run in paragraph.runs:
run.text = ""
if paragraph.runs:
paragraph.runs[0].text = updated_text
# Function to replace the date in the footer
def replace_date_in_footer(doc):
"""Replace the <<DATE2>> placeholder with the current date in the footer."""
current_date = datetime.now().strftime("%d %B %Y")
docx_find_replace_footer(doc, "<<DATE2>>", current_date)
# Define the mapping between placeholders and feature class fields
field_mapping = {
"<<PROJECT_NAME>>": "PROJECT_NAME",
"<<FIELD_DATE>>": "FIELD_DATE",
"<<ARCH_CREW>>": "ARCH_CREW",
"<<PERMIT>>": "PERMIT",
"<<DIVISION>>": "DIVISION",
"<<METHOD>>": "METHOD",
"<<DIST_EXIST>>": "DIST_EXIST",
"<<DESCRIPTION>>": "DESCRIPTION",
"<<DIST_REQ>>": "DIST_REQ",
"<<HISTORY>>": "HISTORY",
"<<SUB_OB>>": "SUB_OB",
"<<ARCH_OB>>": "ARCH_OB",
"<<REC>>": "REC"
}
# Get the feature class fields
feature_fields = list(field_mapping.values()) + ["last_edited_date"]
# Iterate through the feature class
with arcpy.da.SearchCursor(feature_class, feature_fields) as cursor:
for feature in cursor:
last_edited_date = feature[-1] # Get the last_edited_date field
# Skip records with no last_edited_date
if last_edited_date is None:
print("Skipping record with no last_edited_date.")
continue
project_name_index = feature_fields.index("PROJECT_NAME")
project_name = feature[project_name_index]
# Generate output filename based on PROJECT_NAME
output_filename = os.path.join(outputfolder, f"{project_name}_FieldSummary.docx")
# Check if the document needs to be created or updated
if os.path.exists(output_filename):
# Get the modification time of the existing document
doc_mod_time = datetime.fromtimestamp(os.path.getmtime(output_filename))
# Skip if the document is up-to-date
if doc_mod_time >= last_edited_date:
print(f"Skipping {output_filename}, already up-to-date.")
continue
# Create or update the document
doc = docx.Document(inputfilename)
for placeholder, field in field_mapping.items():
field_index = feature_fields.index(field)
value = feature[field_index]
docx_find_replace_text(doc, placeholder, str(value))
if placeholder in ["<<PROJECT_NAME>>", "<<DESCRIPTION>>"]:
docx_find_replace_header(doc, placeholder, str(value))
# Replace the date in the footer
replace_date_in_footer(doc)
# Save the document
doc.save(output_filename)
print(f"Created or updated: {output_filename}")
print("Process completed.") Thank you kindly for any tips!