Select to view content in your preferred language

Programmatically update metadata

1327
1
06-26-2024 03:33 AM
Labels (1)
HanliePetoors
Frequent Contributor

Hi,

I'm working in ArcGIS Pro 3.3.0.

I have a script that updates an SDE feature class and then I want to update the publication date in the metadata. This is not part of the common metadata properties so it's not directly accessible from a metadata object properties.

I'm using the ISO19139 metadata standard.

My algorithm is:

  1. Create the metadata object.
  2. Export the metadata to XML.
  3. Modify the XML using ElementTree.
  4. Save the modified XML.
  5. Import the modified XML to the metadata object.

My code is:

import xml.etree.ElementTree as ET
from arcpy import metadata as md
import datetime

item = r'D:\Projects\WCG General\Python 2 to 3\DOH_HealthFacilities.gdb\DOH_Facilities_AllHealthSites'
CurrentDate = datetime.datetime.now().strftime("%Y-%m-%d")

currentXMLPath = r'D:\Projects\WCG General\Python 2 to 3\temp.xml'
newXMLPath = r'D:\Projects\WCG General\Python 2 to 3\temp_updated.xml'

# get the item's metadata xml
item_md = md.Metadata(item)
metadata_xml_string = item_md.xml

# export item's metadata
item_md.exportMetadata(outputPath=currentXMLPath,
                metadata_export_option='ISO19139')

# create an ElementTree object and get its root
tree = ET.parse(currentXMLPath)
root = tree.getroot()

# check that the correct element exists
# root[10][0][0][0][2][0][1][0].text must be = 'publication'
# root[10][0][0][0][2][0][0][0] is the field that must be set

# set the value of the publication date to the current date
if root[10][0][0][0][2][0][1][0].text == 'publication':
    root[10][0][0][0][2][0][0][0].text = CurrentDate

# save the changes to the the new XML file
tree.write(newXMLPath)

# import the new XML to the metadata object
item_md.importMetadata(sourceUri=newXMLPath,
                       metadata_import_option='ISO19139')

Everything works fine until the last step, when I get an error

Traceback (most recent call last):
  File "D:\Projects\WCG General\Python 2 to 3\read_metadata.py", line 50, in <module>
    item_md.importMetadata(sourceUri=newXMLPath,
  File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\utils.py", line 186, in fn_
    return fn(*args, **kw)
           ^^^^^^^^^^^^^^^
  File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\metadata.py", line 126, in importMetadata
    return _convertArcObjectToPythonObject(arcgisscripting.metadata.Metadata.importMetadata(*_gp_fixargs((self, sourceUri, metadata_import_option, customStylesheetPath), True)))
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SystemError: <built-in method importMetadata of MetadataObject object at 0x000001B4105315C0> returned a result with an exception set
 
Anybody have any ideas for a better way of doing this or fixing what's going wrong here?
 
Thanks
Hanlie
Tags (1)
1 Reply
JenaF
by
Emerging Contributor

This is probably too late for @HanliePetoors but putting here for future viewers. Below is a function to search for an existing "Publication Date" element and either update the existing date or, if not found, create a new element with the date. I like using element names more than indices because 1) other revisions to the metadata could make the indices invalid and 2) it's easier for my brain to match up what I'm viewing in the xml file with my code. But it does make the code more verbose. All of the {*} in the element names are to avoid writing out the full namespace; I haven't quite figured out how to best deal with those, but wildcards make it clean enough for me.

import arcpy
import datetime
import xml.etree.ElementTree as et

TODAY = datetime.date.today()

# identify the feature class and the metadata xml output location
sde_fc = {path to your feature class of interest}
md_xml = {path you want the metadata xml to export to}

# get the metadata object from the feature class
sde_fc_md = arcpy.metadata.Metadata(sde_fc)

# export the metadata xml to the path specified above
sde_fc_md.exportMetadata(md_xml_path, "ISO19139")

# add/revise the publication date. this will overwrite the xml file in place
add_pub_date(md_xml)

# import the edited xml from the same path into the feature class's metadata
sde_fc_md.importMetadata(md_xml, "ISO19139_UNKNOWN")

# save the metadata
sde_fc_md.save()

# function to create/edit publication date
def add_pub_date(md_xml_path):
msg("adding today as publication date to metadata xml")

# registering the namespaces
et.register_namespace('', 'http://www.isotc211.org/2005/gmd')
et.register_namespace('gco', 'http://www.isotc211.org/2005/gco')

# reading in the xml that has already been exported from Pro
md_xml_tree = et.parse(md_xml_path)
root = md_xml_tree.getroot()

# setting the publication date var, as it will be used in two places
pub_date = str(TODAY)

# getting the parent element for the date element(s)
ci_citation_elem = root.find('./{*}identificationInfo/{*}MD_DataIdentification/{*}citation/{*}CI_Citation')

# look for the publication element because it might already exist
if ci_citation_elem.findall('.//*[.="publication"]'):
msg('found publication date! updating to TODAY')
ci_date_elem = ci_citation_elem.find('.//{*}dateType[{*}CI_DateTypeCode="publication"]/..')
date_subelement = ci_date_elem.find('{*}date/{*}Date')
date_subelement.text = pub_date

# create it if it doesn't exist
else
:
msg("no publication date found; adding today's date")
ci_citation_elem = root.find('./{*}identificationInfo/{*}MD_DataIdentification/{*}citation/{*}CI_Citation')
date_elem = et.SubElement(ci_citation_elem, 'date')
ci_date_elem = et.SubElement(date_elem, 'CI_Date')
date_subelem = et.SubElement(ci_date_elem, 'date')
date_subsubelem = et.SubElement(date_subelem, 'gco:Date')
date_subsubelem.text = pub_date
datetype_subelem = et.SubElement(ci_date_elem, 'dateType')
ci_datetypecode_subelem = et.SubElement(datetype_subelem, 'CI_DateTypeCode')
ci_datetypecode_subelem.attrib = {'codeList': 'http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode',
'codeListValue': 'publication',
'codeSpace': 'ISOTC211/19115'}
ci_datetypecode_subelem.text = 'publication'

# write the revised tree back to file
md_xml_tree.write(md_xml_path,
encoding='utf-8',
xml_declaration=True)


 

0 Kudos