Solved! Go to Solution.
For future coders looking for "one" solution to this problem, I'm placing a short version of my final python solution.
Thanks to Heidi Kristenson for help with setting the thumbnail in the xml.
Problem: Update metadata on a geodatabase feature class from metadata maintained in a separate table. Include a thumbnail from an already created jpeg file.
Solution: Export the metadata from the target feature class to a scratch XML file. Modify the xml file elements with the new metadata values as well as the thumbnail. Import the modified metadata back into the target geodatabase feature class.
Of course, our solution iterates through a list of geodatabase feature classes to update the metadata which this sample does not illustrate for simplicity.
import os
import arcpy
import xml.etree.ElementTree as ET
import base64
from pyodbc import connect as odbcconn
from pandas import read_sql_query as readsqlqry
num_elements = 0
featName = 'your_featureClassName'
fcPathName = 'Database Connections/your_geodatabase.sde/' + featName
# set up a connection to read user maintained metadata from a SQL Server table
metaConnStr = 'DRIVER={SQL Server};SERVER=servername;DATABASE=dbname;Trusted_Connection=yes'
conn = odbcconn(metaConnStr)
# your metadata source data will differ from the following
metaqry = 'SELECT [FULL_NAME],[COVER_NAME],[ABSTRACT],[UPDATEDATE],[OWNERNAME]' +\
',[PATH],[METAACCESS],[ONMAINT],[MAINTFREQ],[KNOWNERROR],[LINEAGE]' +\
',[DOMAIN],[RECTIFIED],[MAINTORG],[MAINTDESC],[LIBINPUT],[SOURCNAME]' +\
',[SOURCCONTACT],[SOURCDOCNAME],[SOURCDATE],[SOURCSCALE],[SOURCFORMAT]' +\
',[SOUR2NAME],[SOUR2CONTACT],[SOUR2DOCNAME],[SOUR2DATE],[SOUR2SCALE]' +\
',[SOUR2FORMAT],[ONMG],[MGLAYERNAME],[MGSCALELOW],[MGSCALEHIGH] ' +\
'FROM [dbo].[metadata] WHERE [COVER_NAME] = \'' + featName + '\''
df_FCMeta = readsqlqry(metaqry, conn) # load query result to pandas dataframe
df_row = df_FCMeta.iloc[0] # get the one row in the dataframe. There is only one row per COVER_NAME
arcpy.env.overwriteOutput = True
# export the ESRI generated metadata from the target feature class
# install location
dir = arcpy.GetInstallInfo('desktop')['InstallDir']
# stylesheet to use
copy_xslt = r'{0}'.format(os.path.join(dir,'Metadata\Stylesheets\gpTools\exact copy of.xslt'))
# temporary XML file
xmlfile = arcpy.CreateScratchName('.xml',workspace=arcpy.env.scratchFolder)
# export xml
arcpy.XSLTransform_conversion(fcPathName, copy_xslt, xmlfile, '')
# get the tree object and root element from the exported xml file
tree = ET.parse(xmlfile)
root = tree.getroot()
# get the dataIdInfo element
dataIdInfoEl = root.find('dataIdInfo')
# dataIdInfo purpose element
# Create the needed purpose xml element
subEl = ET.SubElement(dataIdInfoEl,'idPurp')
subEl.text = df_row['FULL_NAME']
num_elements += 1
# dataIdInfo abstract element
# Create the needed abstract xml element
subEl = ET.SubElement(dataIdInfoEl,'idAbs')
subEl.text = df_row['ABSTRACT']
num_elements += 1
# import the thumbnail image (jpg) from a file folder by name. Thumbnail file must exist (created by a separate process)
thumbnailsPath = 'c:/thumbnails/'
jpgFile = thumbnailsPath + featName + '.jpg'
if os.path.exists(jpgFile):
with open(jpgFile, "rb") as img_file:
strEncoded = base64.b64encode(img_file.read())
# Create the needed thumbnail xml element
attrib = {'EsriPropertyType':'PictureX'}
subEl = ET.SubElement(root,'Binary')
subEl = ET.SubElement(subEl,'Thumbnail')
subEl = ET.SubElement(subEl,'Data', attrib)
subEl.text = strEncoded
num_elements += 1
if num_elements > 0:
# save modifications to XML
tree.write(xmlfile)
arcpy.MetadataImporter_conversion(xmlfile, fcPathName)
else:
print('No changes to save')
There are no arcpy classes or functions at present, so you might want to jump on these for support
Arcpy metadata editing functions
https://community.esri.com/ideas/14249
plus a few others
Thanks for the links Dan.
I found the answer I was looking for here.
https://community.esri.com/message/890233-re-embed-a-thumbnail-in-xml-for-item-description?commentID=890233&et=watches.email.thread#comment-890233
Harlan Marshall
GIS Analyst – Senior
Pima County
(520) 724-6757
I am using Arcpy Metadata Editor to update our metada in Shape Files and feature classes in Filegeodb format.
I am not sure it will work with SQL Server.
Thanks for your answer. I was actually looking for a programmatic way to update metadata.
Harlan Marshall
GIS Analyst – Senior
Pima County
(520) 724-6757
For future coders looking for "one" solution to this problem, I'm placing a short version of my final python solution.
Thanks to Heidi Kristenson for help with setting the thumbnail in the xml.
Problem: Update metadata on a geodatabase feature class from metadata maintained in a separate table. Include a thumbnail from an already created jpeg file.
Solution: Export the metadata from the target feature class to a scratch XML file. Modify the xml file elements with the new metadata values as well as the thumbnail. Import the modified metadata back into the target geodatabase feature class.
Of course, our solution iterates through a list of geodatabase feature classes to update the metadata which this sample does not illustrate for simplicity.
import os
import arcpy
import xml.etree.ElementTree as ET
import base64
from pyodbc import connect as odbcconn
from pandas import read_sql_query as readsqlqry
num_elements = 0
featName = 'your_featureClassName'
fcPathName = 'Database Connections/your_geodatabase.sde/' + featName
# set up a connection to read user maintained metadata from a SQL Server table
metaConnStr = 'DRIVER={SQL Server};SERVER=servername;DATABASE=dbname;Trusted_Connection=yes'
conn = odbcconn(metaConnStr)
# your metadata source data will differ from the following
metaqry = 'SELECT [FULL_NAME],[COVER_NAME],[ABSTRACT],[UPDATEDATE],[OWNERNAME]' +\
',[PATH],[METAACCESS],[ONMAINT],[MAINTFREQ],[KNOWNERROR],[LINEAGE]' +\
',[DOMAIN],[RECTIFIED],[MAINTORG],[MAINTDESC],[LIBINPUT],[SOURCNAME]' +\
',[SOURCCONTACT],[SOURCDOCNAME],[SOURCDATE],[SOURCSCALE],[SOURCFORMAT]' +\
',[SOUR2NAME],[SOUR2CONTACT],[SOUR2DOCNAME],[SOUR2DATE],[SOUR2SCALE]' +\
',[SOUR2FORMAT],[ONMG],[MGLAYERNAME],[MGSCALELOW],[MGSCALEHIGH] ' +\
'FROM [dbo].[metadata] WHERE [COVER_NAME] = \'' + featName + '\''
df_FCMeta = readsqlqry(metaqry, conn) # load query result to pandas dataframe
df_row = df_FCMeta.iloc[0] # get the one row in the dataframe. There is only one row per COVER_NAME
arcpy.env.overwriteOutput = True
# export the ESRI generated metadata from the target feature class
# install location
dir = arcpy.GetInstallInfo('desktop')['InstallDir']
# stylesheet to use
copy_xslt = r'{0}'.format(os.path.join(dir,'Metadata\Stylesheets\gpTools\exact copy of.xslt'))
# temporary XML file
xmlfile = arcpy.CreateScratchName('.xml',workspace=arcpy.env.scratchFolder)
# export xml
arcpy.XSLTransform_conversion(fcPathName, copy_xslt, xmlfile, '')
# get the tree object and root element from the exported xml file
tree = ET.parse(xmlfile)
root = tree.getroot()
# get the dataIdInfo element
dataIdInfoEl = root.find('dataIdInfo')
# dataIdInfo purpose element
# Create the needed purpose xml element
subEl = ET.SubElement(dataIdInfoEl,'idPurp')
subEl.text = df_row['FULL_NAME']
num_elements += 1
# dataIdInfo abstract element
# Create the needed abstract xml element
subEl = ET.SubElement(dataIdInfoEl,'idAbs')
subEl.text = df_row['ABSTRACT']
num_elements += 1
# import the thumbnail image (jpg) from a file folder by name. Thumbnail file must exist (created by a separate process)
thumbnailsPath = 'c:/thumbnails/'
jpgFile = thumbnailsPath + featName + '.jpg'
if os.path.exists(jpgFile):
with open(jpgFile, "rb") as img_file:
strEncoded = base64.b64encode(img_file.read())
# Create the needed thumbnail xml element
attrib = {'EsriPropertyType':'PictureX'}
subEl = ET.SubElement(root,'Binary')
subEl = ET.SubElement(subEl,'Thumbnail')
subEl = ET.SubElement(subEl,'Data', attrib)
subEl.text = strEncoded
num_elements += 1
if num_elements > 0:
# save modifications to XML
tree.write(xmlfile)
arcpy.MetadataImporter_conversion(xmlfile, fcPathName)
else:
print('No changes to save')