Personal tools
You are here: Home Documentation How-tos Geonetwork v2.0.3 shema/template Howto
Document Actions

Geonetwork v2.0.3 shema/template Howto

This How-to applies to: 2.0.3

Howto create and add custom shemas to geonetwork using xml, xsl, xsd and xpath

Before you even start thinking about creating a new schema/template for geonetwork, I strongly suggest you to read all of the tutorial about XML, Xpath, XSL and XSD on w3schools.com

xml : http://www.w3schools.com/xml/default.asp
xpath : http://www.w3schools.com/xpath/xpath_syntax.asp
xsl : http://www.w3schools.com/xsl/xsl_languages.asp
xsd : http://www.w3schools.com/schema/default.asp

Otherwise, you will probably get confused and never be able to fully understand what you’re doing.


Geonetwork’s schema’s are the root element of all stored metadata. Based on a schema, the user can then create his custom templates. Schema uses a combination of XML technologies to store, edit and display metadata. This dynamic way to store and to show metadata makes it very flexible and, most of all, it will be compatible with any new future devices like blackberries, iphone, cellphones, etc.

Back to top

1 – General structure : organisation_template.xml

Create a folder named exactly like your template name « organisation » in [geonet_root]/web/xml/schemas/ Here you will store various files mandatory to any geonetwork schema.

Start by thinking and writing down the XML structure of the metadata you would like to show with your schema. Let say I want to add a schema that let geonetwork users enter information about any organisation. The basic XML would look like this.

*Note that any metadata file that is published in geonetwork MUST have a unique universal id (UUID). The schema you’re creating will need one, since geonetwork considers schema as an other metadata. To get one, you can visit the International Telecommunication Union at : http://www.itu.int/ITU-T/asn1/cgi-bin/uuid_generate

*Note that according to the w3c standard, all xml files must start with <?xml version="1.0" encoding="UTF-8"?>. Since this file will be place in the database and rearranged by the geonetwork’s api implementation, there is no need for the xml version declaration. Geonetwork will add the appropriate xml version declaration when needed.

<metadata>
    <orgTitle>New organisation</orgTitle>
    <orgAcronym/>
    <orgParentInstitution/>
    <orgDesc/>
    <orgSuppInfo/>
    <orgContactus>
        <orgAddress/>
        <orgPOBox/>
        <orgCity/>
        <orgPostalcode/>
        <orgProvince/>
        <orgCountry/>
        <orgPhone/>
        <orgFax/>
        <orgWebsite/>
        <orgEmail/>
    </orgContactus>
    <orgContactInfo>
        <orgContactName/>
        <orgContactRole/>
        <orgContactEmail/>
        <orgContactPhone/>
    </orgContactInfo>
    <mdFileID/>
</metadata>

Save this file as “organisation_template.xml”… you’ll need it later.

Note that what’s written in your template tag <orgTitle> will be displayed in the dropdown list of available templates when user creates new metadata.

Back to top

2 – Language specific tags : /web/loc/[lang]/xml/organisation.xml

Now, create the file “organisation.xml” that will be placed in “[geonetwork_root_path]/web/loc/en/xml/”. This file will used to display each metadata header and help information in different languages. So create as many “organisation.xml” in the various localizations your geonetwork interface is available in. Following the example above, it will look like this:

*Note that the “help=” attribute is not always present. This is a personal decision, since most of the fields are self explanatory. However, all fields should be explained.

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <metadata help="root entity which defines metadata about the organisation">Organisation's Metadata</metadata>
    <orgTitle help="The organisation's name">Organisation's name</orgTitle>
    <orgAcronym help="abbreviations that is formed using the initial letters of words or word parts in a name.">Acronym</orgAcronym>
    <orgParentInstitution help="The institution above this organisation, if applicable">Parent institution</orgParentInstitution>
    <orgDesc help="Description of the main goal of the organisation">Description</orgDesc>
    <orgContactus>Contact us</orgContactus>
    <orgAddress>Address</orgAddress>
    <orgPOBox>P.O. Box</orgPOBox>
    <orgCity>City</orgCity>
    <orgPostalcode>Postal Code / Zip</orgPostalcode>
    <orgProvince>Province / State</orgProvince>
    <orgCountry>Country</orgCountry>
    <orgPhone>Phone</orgPhone>
    <orgFax>Fax</orgFax>
    <orgWebsite>Website http://</orgWebsite>
    <orgEmail>Email</orgEmail>
    <orgSuppInfo help="any other descriptive information about the dataset">Supplemental Information</orgSuppInfo>
    <orgContactInfo help="person to contact">Contact name</orgContactInfo>
    <orgContactName>Name</orgContactName>
    <orgContactRole>Position</orgContactRole>
    <orgContactEmail>Email</orgContactEmail>
    <orgContactPhone>Phone and ext.</orgContactPhone>
    <mdFileID help="unique identifier for this metadata file">File identifier</mdFileID>
</root>

***I strongly suggest to write the “help=” attribute right now. If you don’t, you will most likely never do it.

Back to top

3- XSD creation : /web/xml/schemas/organisation/schema.xsd

XSD stands for XML Schema Definition. You will now tell geonetwork how your xml is organized. This is also where you will tell your geonetwork’s api implementation if some element are optional, mandatory, unique or if multiple instance of them car be created. For an exhaustive list of options, visit : http://www.w3schools.com/schema/el_element.asp

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">

    <!-- complex type declaration -->
    <xs:element name="metadata" type="metadata"/>
    <xs:complexType name="metadata">
        <xs:sequence>
            <xs:element ref="orgTitle"/>
            <xs:element ref="orgAcronym"/>
            <xs:element ref="orgParentInstitution"/>
            <xs:element ref="orgDesc"/>
            <xs:element ref="orgSuppInfo"/>
            <xs:element ref="orgContactus"/>
            <xs:element minOccurs="0" maxOccurs="unbounded" ref="orgContactInfo" />
            <xs:element ref="mdFileID"/>
        </xs:sequence>
    </xs:complexType>

    <xs:element name="orgContactInfo" type="orgContactInfo" />
    <xs:complexType name="orgContactInfo">
        <xs:sequence>
            <xs:element ref="orgContactName"/>
            <xs:element ref="orgContactRole"/>
            <xs:element ref="orgContactEmail"/>
            <xs:element ref="orgContactPhone"/>
        </xs:sequence>
    </xs:complexType>

    <xs:element name="orgContactus" type="orgContactus"/>
    <xs:complexType name="orgContactus">
        <xs:sequence>
            <xs:element ref="orgAddress"/>
            <xs:element ref="orgPOBox"/>
            <xs:element ref="orgCity"/>
            <xs:element ref="orgPostalcode"/>
            <xs:element ref="orgProvince"/>
            <xs:element ref="orgCountry"/>
            <xs:element ref="orgPhone"/>
            <xs:element ref="orgFax"/>
            <xs:element ref="orgWebsite"/>
            <xs:element ref="orgEmail"/>
        </xs:sequence>

    </xs:complexType>

    <!-- ELEMENT DECLARATIONS -->
    <xs:element name="orgTitle" type="xs:string"/>
    <xs:element name="orgAcronym" type="xs:string"/>
    <xs:element name="orgDesc" type="xs:string"/>
    <xs:element name="orgParentInstitution" type="xs:string"/>
    <xs:element name="orgAddress" type="xs:string"/>
    <xs:element name="orgPOBox" type="xs:string"/>
    <xs:element name="orgCity" type="xs:string"/>
    <xs:element name="orgPostalcode" type="xs:string"/>
    <xs:element name="orgProvince" type="xs:string"/>
    <xs:element name="orgCountry" type="xs:string"/>
    <xs:element name="orgPhone" type="xs:string"/>
    <xs:element name="orgFax" type="xs:string"/>
    <xs:element name="orgWebsite" type="xs:string"/>
    <xs:element name="orgEmail" type="xs:string"/>
    <xs:element name="orgContactName" type="xs:string"/>
    <xs:element name="orgContactPhone" type="xs:string"/>
    <xs:element name="orgContactEmail" type="xs:string"/>
    <xs:element name="orgContactRole" type="xs:string"/>
    <xs:element name="orgSuppInfo" type="xs:string"/>
    <xs:element name="mdFileID" type="xs:string"/>
</xs:schema>

Back to top

4- Geonetwork specific stylesheet files : /web/xml/schemas/organisation/…

Geonetwork’s api will need few xsl files in your schema’s folder in order to perform various operations such as getting the uuid or the thumbnail. Here is a very simple version of the each files needed. You can just copy paste them. Perhaps, more complexes operations can be done. I suggest looking at the fgdc-std or iso19115 files for complete examples.

extract-thumbnails.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="metadata">
        <thumbnail/>
    </xsl:template>
</xsl:stylesheet>

extract-uuid.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="metadata">
        <uuid><xsl:value-of select="mdFileID"/></uuid>
    </xsl:template>
</xsl:stylesheet>

schema-suggestions.xml

this file seam to be there for informative purposes, leave-it blank

<?xml version="1.0" encoding="UTF-8"?>
<fields>
    <!-- <field name="">
        <suggest name=""/>
    </field>
    -->
</fields>

set-thumbnail.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/root">
        <xsl:apply-templates select="metadata"/>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

unset_thumbnail.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/root">
        <xsl:apply-templates select="metadata"/>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

update-fixed-info.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/root">
        <xsl:apply-templates select="metadata"/>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Back to top

5- Geonetwork’s searching stylesheet : /web/xml/search/organisation.xsl

By default, Geonetwork’s search engine will search the “title”, “abstract”, “keywords” and “geographic box”. So you need to match at least one of those with your metadata schema. In our organisation example, there is no coverage region or keywords, but you can look at the other templates.

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <Document>

            <xsl:apply-templates select="/metadata/orgTitle">
                <xsl:with-param name="name" select="'title'"/>
                <xsl:with-param name="token" select="'true'"/>
            </xsl:apply-templates>

            <xsl:apply-templates select="/metadata/orgDesc">
                <xsl:with-param name="name" select="'abstract'"/>
                <xsl:with-param name="token" select="'true'"/>
            </xsl:apply-templates>

            <Field name="any" store="false" index="true" token="true">
                <xsl:attribute name="string">
                    <xsl:apply-templates select="/metadata" mode="allText"/>
                </xsl:attribute>
            </Field>

            <!-- locally searchable fields -->
            <!-- defaults to true -->
            <Field name="digital" string="true" store="false" index="true" token="false"/>
        </Document>
    </xsl:template>

<!-- text element, by default indexed, not stored nor tokenized -->
    <xsl:template match="*">
        <xsl:param name="name" select="name(.)"/>
        <xsl:param name="store" select="'false'"/>
        <xsl:param name="index" select="'true'"/>
        <xsl:param name="token" select="'false'"/>
        <Field name="{$name}" string="{string(.)}" store="{$store}" index="{$index}" token="{$token}"/>
    </xsl:template>

<!-- codelist element, indexed, not stored nor tokenized -->
    <xsl:template match="*[./*/@value]">
        <xsl:param name="name" select="name(.)"/>
        <Field name="{$name}" string="{*/@value}" store="false" index="true" token="false"/>
    </xsl:template>

<!--allText -->
    <xsl:template match="*" mode="allText">
        <xsl:for-each select="@*"><xsl:value-of select="concat(string(.),' ')"/></xsl:for-each>
            <xsl:choose>
                <xsl:when test="*"><xsl:apply-templates select="*" mode="allText"/></xsl:when>
                <xsl:otherwise><xsl:value-of select="concat(string(.),' ')"/></xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    </xsl:stylesheet>

Back to top

6- Your own Schema’s Stylesheet : /web/xsl/metadata-organisation.xsl

This is the file you can end up playing with for days without knowing what you’re doing… and… on top of that… expecting to have some results. I wish no body will ever go through those days after me, this is why I’m writing this document.

This is the stylesheet that will be used by geonetwork to show the content of your metadata according to user’s request for viewing or editing it. In both case, it is possible for the user to choose between the “simple”, “advanced” or “xml” view. Depending on what the user is doing with the metadata, we need to show it different ways. Note that there is no need for any specification in the “xml” view, since we simply show the raw metadata in it’s xml form.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:geonet="http://www.fao.org/geonetwork">

<!--
default: in simple mode just a flat list
-->
    <xsl:template mode="organisation" match="*|@*">
        <xsl:param name="schema"/>
        <xsl:param name="edit"/>
        <xsl:apply-templates mode="element" select=".">
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="edit" select="$edit"/>
            <xsl:with-param name="flat" select="$currTab='simple'"/>
        </xsl:apply-templates>
    </xsl:template>

<!--
these elements should be boxed
-->
    <xsl:template mode="organisation" match="orgContactInfo|orgContactus">
        <xsl:param name="schema"/>
        <xsl:param name="edit"/>
        <xsl:apply-templates mode="complexElement" select=".">
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="edit" select="$edit"/>
        </xsl:apply-templates>
    </xsl:template>

<!--
make the following fields always not editable:
mdFileID
-->
    <xsl:template mode="organisation" match="mdFileID">
        <xsl:param name="schema"/>
        <xsl:param name="edit"/>
        <xsl:apply-templates mode="element" select=".">
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="edit" select="false()"/>
        </xsl:apply-templates>
    </xsl:template>

<!--
orgDesc, orgSuppInfo
-->
   <xsl:template mode="organisation" match="orgDesc|orgSuppInfo">
        <xsl:param name="schema"/>
        <xsl:param name="edit"/>
        <xsl:apply-templates mode="simpleElement" select=".">
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="edit" select="$edit"/>
            <xsl:with-param name="text">
                <xsl:call-template name="getElementText">
                    <xsl:with-param name="schema" select="$schema"/>
                    <xsl:with-param name="edit" select="$edit"/>
                    <xsl:with-param name="rows" select="5"/>
                </xsl:call-template>
           </xsl:with-param>
        </xsl:apply-templates>
    </xsl:template>

<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- organisation brief formatting -->
<!-- this formating is used to show search results -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <xsl:template name="organisationBrief">
        <metadata>
            <title><xsl:value-of select="orgTitle"/></title>
            <abstract><xsl:value-of select="orgDesc"/></abstract>
            <xsl:copy-of select="geonet:info"/>
        </metadata>
    </xsl:template>
</xsl:stylesheet>

Back to top

7- Modifying of geonetwork’s config files.

/web/WEB-INF/config.xml

Add this line into the <gui> section :

<xml name="organisation" file="xml/organisation.xml" />

/web/xsl/metadata-edit.xsl

if you want your metadata schema to have a thumbnail, add a line like this into the “edit button” template section (<xsl:template name="editButtons" …>):

<!-- thumbnails -->
<xsl:if test="string(geonet:info/schema)='organisation'">
    &#160;
    <button class="content" onclick="doAction('{/root/gui/locService}/metadata.thumbnail.form')">
        <xsl:value-of select="/root/gui/strings/thumbnails"/>
    </button>
</xsl:if>

/web/xsl/metadata-utils.xsl

Add this line at the top :

<xsl:include href="metadata-organisation.xsl"/>

and this line into the <!-- brief --> section:

<!-- organisation -->
<xsl:when test="$schema='organisation'">
    <xsl:call-template name="organisationBrief"/>
</xsl:when>

/web/xsl/metadata.xsl

Add these lines into the <!-- main schema switch -->

<!-- organisation -->
<xsl:when test="$schema='organisation'">
    <xsl:apply-templates mode="organisation" select="." >
        <xsl:with-param name="schema" select="$schema"/>
        <xsl:with-param name="edit" select="$edit"/>
    </xsl:apply-templates>
</xsl:when>

Back to top

8 – Database integration (I’m using SQLYog)

A) metadata table

Add organisation_template.xml to your table.

Make sure the id is unique

schemaid must be your schema’s name “organisation”

isTemplate must be set to “y

data must be an exact copy of organisation_template.xml (see section “1 – General structure“). If you worry about the tabs and carriage returns, just delete them.

uuid, you can have your own generated by the International Telecommunication Union at :

http://www.itu.int/ITU-T/asn1/cgi-bin/uuid_generate

SQL statement example:

insert into `metadata`

(`id`,`schemaId`,`isTemplate`,`createDate`,`lastChangeDate`,`data`,`source`,`sourceUri`,`uuid`)

values ( '30', 'organisation' ,'y', '2007-06-21T15:21:47', '2007-06-21T15:21:47' ,'<metadata><orgTitle>New organisation</orgTitle><orgAcronym/><orgParentInstitution/><orgDesc/><orgSuppInfo/><orgContactus><orgAddress/><orgPOBox/><orgCity/><orgPostalcode/><orgProvince/><orgCountry/><orgPhone/><orgFax/><orgWebsite/><orgEmail/></orgContactus> <orgContactInfo><orgContactName/><orgContactRole/><orgContactEmail/><orgContactPhone/> </orgContactInfo> <mdFileID>d5750700-1da8-11dc-95c5-0002a5d5c51b</mdFileID></metadata>','myGeoNet',NULL,'d5750700-1da8-11dc-95c5-0002a5d5c51b')

B) operationallowed table

The default groupId to give access to is “2”

The metadataId is 30 (see above)

The operationId is by default 0,1,2,4,5,6

(Do I need to specify to make one entry per operationId?)

Back to top

9 – Testing

Connect to your geonetwork, choose your new schema, and create a new metadata!

by crayco last modified 2008-07-17 10:40 Creative Commons - http://creativecommons.org/licenses/by/2.5/

Creative Commons License
This work is licensed under a Creative Commons Attribution-No Derivative Works 3.0 Unported License.

Powered by Plone CMS, the Open Source Content Management System