Skip to content

Metadata Massive Replace

josegar74 edited this page May 23, 2014 · 7 revisions
Date Apr 22 2014 Contacts Jose García/Juan Luis Rodríguez
Status Motion passed / Done Release 2.12
Resources Available Ticket # https://github.com/geonetwork/core-geonetwork/issues/471
Source code https://github.com/geonetwork/core-geonetwork/pull/472
Funding Ontario Ministry of Natural Resources (OMNR), Environment Canada

Overview

This proposal adds a new feature to apply a massive replacement process in the content of metadata records selection. The feature is focussed in iso19139 metadata, but can be extended in the future to other non iso19139 profiles.

The user can select a set of metadata records and define the replacements to apply from a predefined list of fields classified in sections:

ExtJS widgets UI

Metadata massive replace menu entry

Metadata massive replace form

The feature allows to test the replacements before applying them, getting a report with all the metadata records updated and the individual change(s) applied to each metadata.

Metadata massive replace report

Other approach for massive update can be to use XLinks to reference contacts and other sections in the metadata that can require massive updates for example if a phone number changes or the responsible of the metadata leaves the organisation, but not always is an option for users to use XLinks.

AngularJS UI

The Massive replacements have been integrated in the Administration panel, in Tools > Batch process:

![Metadata massive replace form - Angular UI] (https://raw.githubusercontent.com/geonetwork/wiki_images/master/proposals/metadata-massive-replace/metadata-massive-replace-form-angularui.png)

![Metadata massive replace report - Angular UI] (https://raw.githubusercontent.com/geonetwork/wiki_images/master/proposals/metadata-massive-replace/metadata-massive-replace-report-angularui.png)

The feature works as described in the previous section for the ExtJS widgets UI.

Technical Details:

ExtJS widgets UI

The list of fields to replace is defined in a translations file using this format (field key, field label). These elements are used to build the user interface:

 <section id="Metadata">
      <field key="id.contact.individualName">Contact > Individual Name</field>
      <field key="id.contact.organisationName">Contact > Organization Name</field>

       ... more fields
 </section>

 <section id="Identification">
      <field key="id.dataid.abstract">Data Identification > Abstract</field>
      <field key="id.dataid.purpose">Data Identification > Purpose</field>

      ... more fields
 </section>

AngularUI

web-ui/src/main/resources/catalog/config/batch-process-cfg.json

Added a new property type with these possible values:

  • fixed-params: value used for existing processes.
{
    "key": "contact-updater",
    "type": "fixed-params",
    "params": [
        {"name": "emailToSearch", "value": "", "type": "email"},
        {"name": "contactAsXML", "value": "", "type": "textarea"}
    ]
}
  • template: value used for the batch replacement process. This value allows to configure the templates that handle the UI for the process.
{
    "key": "batch-replacer",
    "type": "template",
    "template": "../../catalog/templates/admin/tools/batch-replacer.html",
    "reportTemplate": "../../catalog/templates/admin/tools/batch-replacer-report.html"
}

web-ui/src/main/resources/catalog/templates/admin/tools/batch.html: Added code to handle the processes with custom templates:

<!-- Render the process UI -->
<div data-ng-switch="selectedProcess.type">
    <!-- fixed-params: render the parameters defined for the process -->
	<div data-ng-switch-when="fixed-params">
		<div data-ng-repeat="p in selectedProcess.params track by $index" data-ng-switch=""
  			data-on="p.type" class="form-group">
  			... 
  		</div>
  	</div>
  	
  	<!-- Render the template with the process UI --> 
  	<div data-ng-switch-when="template">
		<div data-ng-include="selectedProcess.template">
		</div>
  	</div>
</div> 

<!-- Render of the process report -->
<div data-ng-switch="selectedProcess.type">
    <div class="col-lg-12" data-ng-hide="!processing && !processReport" id="gn-batch-process-report" data-ng-switch-when="fixed-params">
    	...
    </div>
    
    <div data-ng-switch-when="template">
      <div data-ng-include="selectedProcess.reportTemplate">
      </div>
	</div>
</div>

web-ui/src/main/resources/catalog/js/admin/AdminToolsController.js: Defines the packages/elements for the replacements.

$scope.batchReplacerGroups = {
        "metadata": {
            "elements": [
              "id.contact.individualName",
             ...
        "data-identification": {
            "elements": [
              "id.dataid.abstract",
              "id.dataid.purpose",
              "id.dataid.keyword",
              ...

Translations for the different packages/elements are defined in the translation files: web-ui/src/main/resources/catalog/locales/en-admin.json

    "batchreplacer-section-metadata": "Metadata",
    "batchreplacer-section-data-identification": "Data Identification",
    "batchreplacer-section-service-identification": "Service Identification",
    "batchreplacer-section-maintenance-information": "Maintenance Information",
    "batchreplacer-section-content-information": "Content Information",
    "batchreplacer-section-distribution-information": "Distribution Information",

    "batchreplacer-el-id.contact.individualName": "Contact > Individual Name",
    "batchreplacer-el-id.contact.organisationName": "Contact > Organization Name",
    "batchreplacer-el-id.contact.voicePhone": "Contact > Voice phone",

Replacement process

In the iso19139 schema has been added a xslt massive-content-update.xsl in the process folder. This xslt receives an xml content with the list of replacements and applies it to the selected metadata:

List of replacements received by the process, for each replacement are defined these values:

  • Field identifier
  • Search value
  • Replace value
<replacements>
  <replacement>
    <field>id.contact.individualName</field>
    <searchValue>John</searchValue>
    <replaceValue>Jennifer</replaceValue>
  </replacement>

  <replacement>
    <field>id.contact.voicePhone</field>
    <searchValue>44455454</searchValue>
    <replaceValue>35445524</replaceValue>
  </replacement>
</replacements>

The process applies the replacements and annotates the xml fields updated so can be displayed in the results report:

    <!-- METADATA CONTACT updates: gmd:MD_Metadata/gmd:contact -->
    <!-- individualName -->
    <xsl:template match="gmd:MD_Metadata/gmd:contact/gmd:CI_ResponsibleParty/gmd:individualName">
        <xsl:call-template name="replaceField">
            <xsl:with-param name="fieldId">id.contact.individualName</xsl:with-param>
        </xsl:call-template>
    </xsl:template>

Here is a simplified snippet of the replacement template to highlight the checks done to apply a replacement and the annotation of a change in the field content:

    <xsl:template name="replaceField">
        <xsl:param name="fieldId" />

        <xsl:copy>
            <xsl:copy-of select="@*" />
			<xsl:choose>
				<!-- If there's a replacement for this field applied -->
				<xsl:when test="$replacements/replacements/replacement[field = $fieldId] and string($replacements/replacements/replacement[field = $fieldId]/searchValue)">


					<xsl:variable name="currentVal" select="gco:CharacterString"  />
					<xsl:variable name="newVal" select="replace(gco:CharacterString, $replacements/replacements/replacement[field = $fieldId]/searchValue, $replacements/replacements/replacement[field = $fieldId]/replaceValue, $case_insensitive)"  />
					
					<!-- If the field content has change --> annotate the change --->
					<xsl:if test="$currentVal != $newVal">
						<xsl:attribute name="geonet:change" select="$fieldId" />
						<xsl:attribute name="geonet:original" select="$currentVal" />
						<xsl:attribute name="geonet:new" select="$newVal" />
					</xsl:if>
					<xsl:value-of select="$newVal" />				  

				</xsl:when>

                                <!-- No replacement for the field, just copy it --> 
				<xsl:otherwise>
					<xsl:apply-templates select="@*|node()"/>
				</xsl:otherwise>
			</xsl:choose>
        </xsl:copy>
    </xsl:template>

Proposal Type:

  • Type: Search-UI
  • Module: services, web-client, web

Voting History

  • Vote Proposed: 24 april 2014
  • +1 from Patrizia, Francois, Jose

Participants

  • Jose García
  • Juan Luis Rodríguez
Clone this wiki locally