创建元数据之后,其中包含的信息将会随时间而变化。如果信息特定于某一个 ArcGIS 项,您可以编辑其元数据,以对该信息进行更改。但如果所更改的信息包括在多个 ArcGIS 项的元数据中,手动编辑所有受影响项的元数据的过程将会十分繁琐。幸运的是,可以使用多种不同的方法同时更新多个项的元数据。
无论 ArcGIS 项如何存储元数据,均认为该信息在 ArcGIS 项内部。当您请求 ArcGIS 项提供元数据时,ArcGIS 项将以 XML 文档的形式提供该信息。可以使用两种常规方法来更新所提供 XML 文档中存储的元数据。更改 XML 文件内容的最常用方法是使用 XSLT 样式表。还可以通过编程方式来修改 XML 文件。使用这两种方法时,必须先将 XML 文档保存到 XML 文件中。然后,可以通过 XSLT 样式表(例如 Python 脚本)或者编程方式来修改 XML 文件的内容。
创建 XSLT 样式表来更新元数据
可以使用自定义 XSLT 样式表来更新项的元数据内容。可以使用如下所示的模型,利用 XSLT 变换工具所选择的 XSLT 样式表首先处理项的元数据。该过程的结果将保存到一个 XML 文件。然后,模型使用元数据导入程序工具将已更新的 XML 文档作为其元数据保存回原始 ArcGIS 项中。
Internet 上有许多可帮助您学习如何创建自定义 XSLT 样式表的资源。然而,下面的示例对入门还是很有帮助的。这些示例介绍了如何更改组织的联系信息。
假设原始元数据包括元数据联系信息(如下所示),其中以下表述均为真:
- 个人姓名为 Reception。
- 组织名称为 Esri Learning Center。
- 街道地址为 380 New York St.
- 城市为 Redlands。
- 州为加利福尼亚,CA。
- 邮政编码为 92373。
- 国家为美国,US。
- 电子邮件地址为 info@esri.com。
- 电话号码为 909-793-2853。
- 传真号码为 909-793-4801。
- 此联系人的指定角色为发布者,010。
必须更新组织联系信息的元数据 XML 文档的摘录。
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<mdContact>
<rpIndName>Reception</rpIndName>
<rpOrgName>Esri Learning Center</rpOrgName>
<rpCntInfo>
<cntAddress>
<delPoint>380 New York St.</delPoint>
<city>Redlands</city>
<adminArea>CA</adminArea>
<postCode>92373</postCode>
<country>US</country>
<eMailAdd>info@esri.com</eMailAdd>
</cntAddress>
<cntPhone>
<voiceNum>909-793-2853</voiceNum>
<faxNum>909-793-4801</faxNum>
</cntPhone>
</rpCntInfo>
<role>
<RoleCd value="010"/>
</role>
</mdContact>
...
</metadata>
在这种情况下,必须按以下方式编辑此联系信息:
- 移除联系信息中的个人姓名。
- 将邮政编码更改为 92373-8100。
- 将电子邮件地址更改为 LearnGIS@esri.com。
- 将电话号码更改为 888-377-4575 x.1-3204。
- 添加用于在 Internet 上查找信息的网页的地址 http://www.esri.com/training。
- 添加可以联系组织的时间信息 8:00am to 5:00pm Pacific Time。
其余联系信息保持不变。
下面的 XSLT 样式表将执行这些编辑。个人姓名元数据元素将被移除。一次更新整个地址及其所有单独元数据元素。将电话号码分别在其余电话信息中进行更新。要添加网页和可用时间,必须复制其他所有现有联系信息,这样,这些信息便不会在新信息添加之前丢失。
以下是编辑某组织的联系信息并复制所有其他元数据内容的 XSLT 样式表。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="no" />
<!-- process the metadata using the templates below -->
<xsl:template match="/">
<xsl:apply-templates select="node() | @*" />
</xsl:template>
<!-- copy all metadata conent -->
<xsl:template match="node() | @*" priority="0">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<!-- all metadata XSLT stylesheets used to update metadata should be identical to this example up to this point -->
<!-- add the templates you'll use to update the metadata below -->
<!-- remove the individual name from the contact information for the organization name Esri Learning Center -->
<xsl:template match="rpIndName[../rpOrgName = 'Esri Learning Center']" priority="1" >
</xsl:template>
<!-- edit the address for any contact with the organization name Esri Learning Center -->
<xsl:variable name="newAddress" >
<cntAddress>
<delPoint>380 New York St.</delPoint>
<city>Redlands</city>
<adminArea>CA</adminArea>
<postCode>92373-8100</postCode>
<country>US</country>
<eMailAdd>LearnGIS@esri.com</eMailAdd>
</cntAddress>
</xsl:variable>
<xsl:template match="cntAddress[../../rpOrgName = 'Esri Learning Center']" priority="1" >
<xsl:copy-of select="$newAddress" />
</xsl:template>
<!-- edit all contacts with the organization name Esri Learning Center to have a new phone number -->
<xsl:variable name="newPhone">888-377-4575 x.1-3204</xsl:variable>
<xsl:template match="voiceNum[../../../rpOrgName = 'Esri Learning Center']" priority="1" >
<voiceNum><xsl:value-of select="$newPhone" /></voiceNum>
</xsl:template>
<!-- add hours of availability for the organization name Esri Learning Center -->
<xsl:template match="rpCntInfo[../rpOrgName = 'Esri Learning Center']" priority="1" >
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
<cntOnlineRes>
<linkage>http://www.esri.com/training</linkage>
</cntOnlineRes>
<cntHours>8:00am to 5:00pm Pacific Time</cntHours>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
使用 XSLT 变换工具将此 XSLT 样式表用于编辑如上所示的示例元数据时,下面的输出 XML 文件将被创建为输出。使用元数据导入程序工具保存原始 ArcGIS 项的这些更改。
下面是由以上 XSLT 样式表生成的已更新元数据的摘录。
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<mdContact>
<rpOrgName>Esri Learning Center</rpOrgName>
<rpCntInfo>
<cntAddress>
<delPoint>380 New York St.</delPoint>
<city>Redlands</city>
<adminArea>CA</adminArea>
<postCode>92373-8100</postCode>
<country>US</country>
<eMailAdd>LearnGIS@esri.com</eMailAdd>
</cntAddress>
<cntPhone>
<voiceNum>888-377-4575 x.1-3204</voiceNum>
<faxNum>909-793-4801</faxNum>
</cntPhone>
<cntOnlineRes>
<linkage>http://www.esri.com/training</linkage>
</cntOnlineRes>
<cntHours>8:00am to 5:00pm Pacific Time</cntHours>
</rpCntInfo>
<role>
<RoleCd value="010"/>
</role>
</mdContact>
...
</metadata>
ArcGIS for Desktop 提供多张 XSLT 样式表以支持转换工具集中的元数据地理处理模型,这些样式表位于 <ArcGIS Installation Location>\Metadata\Stylesheets\gpTools 文件夹中。这些文件可用作示例。
创建您自己的样式表时,最好能够了解您正在使用的 XML 格式。描述 ArcGIS 元数据 XML 格式的 XML DTD 位于 <ArcGIS Installation Location>\Metadata\Translator\Rules 文件夹中。
利用 Python 脚本更新元数据
另一种方法是使用 Python 脚本更新项的元数据内容。Python 脚本必须与上文所述模型执行同一地理处理工具,该模型使用 XSTL 样式表来处理元数据。首先使用了 XSLT 变换工具利用 ArcGIS for Desktop 提供的 exact copy of.xslt 样式表将项的元数据副本保存至 XML 文件。可以利用 Python 脚本对生成的 XML 文件进行修改。然后,必须使用元数据导入程序工具将已更新的 XML 文档作为其元数据保存回原始 ArcGIS 项中。
以下 Python 脚本将更改现有 Purpose 元素(如果存在)中的文本,并添加一个新的 Credits 元素。可使用标准 Python 库中记录的 Python ElementTree API 修改 XML 文档。也可以选择使用其他 Python 包中提供的其他 API 来修改 XML 文件。
该 Python 脚本将更新 Purpose 元素,并向项的元数据添加新的 Credits 元素。
# batch update metadata for datasets in a folder
import os, sys
import arcpy
import xml.etree.ElementTree as ET
# arcpy environments
arcpy.env.overwriteOutput = "True"
# Script arguments...
Source_Metadata = arcpy.GetParameter(0)
# Local variables
# new purpose text
newPurpose = "This is new text for an existing Purpose metadata element."
newCredits = "This is text for a new Credits metadata element."
# 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"))
arcpy.AddMessage("XSLT: {0}".format(copy_xslt))
def update_metadata(root):
num_elements = 0
# modify purpose element's text
# there is only supposed to be one purpose element in metadata
# replace purpose element text if element exists
# if element doesn't exist, do nothing
purposeEls = root.findall(".//idPurp")
for element in purposeEls:
if element.text is not None:
element.text = newPurpose
num_elements += 1
# add credits element to dataIdInfo parent, if the parent exists
# ISO allows many dataIdInfo groups; ArcGIS generally supports only one, get the 1st
# ISO allows many idCredit elements: 1st on Item Description page, all on Resource Details page
# always append new idCredit element to 1st dataIdInfo with appropriate text
# existing idCredit elements remain in place
dataIdInfoEls = root.findall("./dataIdInfo[1]")
for element in dataIdInfoEls:
if element:
newCreditEl = ET.SubElement(element,"idCredit")
newCreditEl.text = newCredits
num_elements += 1
return num_elements
for item in Source_Metadata:
arcpy.AddMessage("Item: {0}".format(item))
# temporary XML file
xmlfile = arcpy.CreateScratchName(".xml",workspace=arcpy.env.scratchFolder)
#arcpy.AddMessage("Temporary XML file: {0}".format(xmlfile))
# export xml
arcpy.XSLTransform_conversion(item, copy_xslt, xmlfile, "")
# read in XML
tree = ET.parse(xmlfile)
root = tree.getroot()
changes = update_metadata(root)
#arcpy.AddMessage("number of elements updated: {0}".format(changes))
if changes > 0:
# save modifications to XML
#arcpy.AddMessage("Saving changes to temporary file...")
tree.write(xmlfile)
# import result back into metadata
arcpy.AddMessage("Saving updated metadata with the item...")
arcpy.MetadataImporter_conversion(xmlfile, item)
else:
arcpy.AddMessage("No changes to save")
arcpy.AddMessage('Finished updating metadata for all source metadata items')