<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:geonet="http://www.fao.org/geonetwork" 
  xmlns:saxon="http://saxon.sf.net/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" 
  xmlns:foaf="http://xmlns.com/foaf/0.1/"
  xmlns:void="http://www.w3.org/TR/void/" 
  xmlns:dcat="http://www.w3.org/ns/dcat#"
  xmlns:dc="http://purl.org/dc/elements/1.1/" 
  xmlns:dct="http://purl.org/dc/terms/"
  xmlns:dctype="http://purl.org/dc/dcmitype/" 
  xmlns:skos="http://www.w3.org/2004/02/skos/core#"
  xmlns:gco="http://www.isotc211.org/2005/gco" 
  xmlns:gmd="http://www.isotc211.org/2005/gmd"
  xmlns:srv="http://www.isotc211.org/2005/srv"
  xmlns:gml="http://www.opengis.net/gml/3.2" 
  xmlns:ogc="http://www.opengis.net/rdf#"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:iso19139="http://geonetwork-opensource.org/schemas/iso19139"
  xmlns:gmi="http://standards.iso.org/iso/19115/-2/gmi/1.0"
  xmlns:gmx="http://www.isotc211.org/2005/gmx" 
  xmlns:gss="http://www.isotc211.org/2005/gss" 
  xmlns:gsr="http://www.isotc211.org/2005/gsr" 
  xmlns:gts="http://www.isotc211.org/2005/gts"
  xmlns:dcterms="http://purl.org/dc/terms/" 
  xmlns:dwc="http://rs.tdwg.org/dwc/terms/"
  xmlns:dwr="http://rs.tdwg.org/dwc/dwcrecord/" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns:gml="http://www.opengis.net/gml/3.2"
  extension-element-prefixes="saxon" exclude-result-prefixes="#all">
<!-- TODO (KDM) : Are all these namespaces strictly necessary? -->

  <!-- TODO : add Multilingual metadata support 
    See http://www.w3.org/TR/2004/REC-rdf-syntax-grammar-20040210/#section-Syntax-languages
    
    TODO : maybe some characters may be encoded / avoid in URIs
    See http://www.w3.org/TR/2004/REC-rdf-concepts-20040210/#dfn-URI-reference
  -->

  <!-- Create reference block to metadata record and dataset to be added in dcat:Catalog usually.  -->
  <!-- FIXME: $url comes from a global variable. -->
  <!-- FIXME: Would be nice to call remplates from iso19139 rather than repeat here -->
	
  <xsl:template match="gmi:MI_Metadata|*[@gco:isoType='gmi:MI_Metadata']" mode="record-reference">
    <!-- TODO : a metadata record may contains aggregate. In that case create one dataset per aggregate member. -->
    <dcat:dataset rdf:resource="{$url}/resource/{iso19139:getResourceCode(.)}"/>
    <dcat:record rdf:resource="{$url}/metadata/{gmd:fileIdentifier/gco:CharacterString}"/>
  </xsl:template>
  
  
  <!--
    Convert ISO record to DCAT
    -->
  <xsl:template match="gmi:MI_Metadata|*[@gco:isoType='gmi:MI_Metadata']" mode="to-dcat">


    <!-- Catalogue records
      "A record in a data catalog, describing a single dataset."        
      
      xpath: //gmd:MD_Metadata|//*[@gco:isoType='gmd:MD_Metadata']
    -->
    <dcat:CatalogRecord rdf:about="{$url}/metadata/{gmd:fileIdentifier/gco:CharacterString}">
      <!-- Link to a dcat:Dataset or a rdf:Description for services and feature catalogue. -->
      <foaf:primaryTopic rdf:resource="{$url}/resource/{iso19139:getResourceCode(.)}"/>

      <!-- Metadata change date.
      "The date is encoded as a literal in "YYYY-MM-DD" form (ISO 8601 Date and Time Formats)." -->
      <xsl:variable name="date" select="substring-before(gmd:dateStamp/gco:DateTime, 'T')"/>
      <dct:issued><xsl:value-of select="$date"/></dct:issued>
      <dct:modified><xsl:value-of select="$date"/></dct:modified>
      <!-- xpath: gmd:dateStamp/gco:DateTime -->
      
      <xsl:call-template name="add-reference">
        <xsl:with-param name="uuid" select="gmd:fileIdentifier/gco:CharacterString"/>
      </xsl:call-template>
    </dcat:CatalogRecord>
    
    <xsl:apply-templates select="gmd:identificationInfo/*" mode="to-dcat"/>
    
  </xsl:template>
  
  <!-- Create all references for ISO19139 record (if rdf.metadata.get) or records (if rdf.search) -->
  <xsl:template match="gmi:MI_Metadata|*[@gco:isoType='gmd:MI_Metadata']" mode="references">
    
    <!-- Keywords -->
    <xsl:for-each-group select="//gmd:MD_Keywords[(gmd:thesaurusName)]/gmd:keyword/gco:CharacterString" group-by=".">
      <!-- FIXME maybe only do that, if keyword URI is available (when xlink is used ?) -->
      <skos:Concept rdf:about="{$url}/thesaurus/{iso19139:getThesaurusCode(../../gmd:thesaurusName)}/{encode-for-uri(.)}">
        <skos:inScheme rdf:resource="{$url}/thesaurus/{iso19139:getThesaurusCode(../../gmd:thesaurusName)}"/>
        <skos:prefLabel><xsl:value-of select="."/></skos:prefLabel>
      </skos:Concept>
    </xsl:for-each-group>
    
    
    <!-- Distribution 
      "Represents a specific available form of a dataset. Each dataset might be available in different 
      forms, these forms might represent different formats of the dataset, different endpoints,... 
      Examples of Distribution include a downloadable CSV file, an XLS file representing the dataset, 
      an RSS feed ..."
      
      Download, WebService, Feed
      
      xpath: //gmd:distributionInfo/*/gmd:transferOptions/*/gmd:onLine/gmd:CI_OnlineResource
    -->
    <xsl:for-each-group select="//gmd:distributionInfo/*/gmd:transferOptions/*/gmd:onLine/gmd:CI_OnlineResource" group-by="gmd:linkage/gmd:URL">
      <dcat:Distribution rdf:about="{gmd:linkage/gmd:URL}">
        <!-- 
          "points to the location of a distribution. This can be a direct download link, a link 
          to an HTML page containing a link to the actual data, Feed, Web Service etc. 
          the semantic is determined by its domain (Distribution, Feed, WebService, Download)." 
        -->
        <dcat:accessURL><xsl:value-of select="gmd:linkage/gmd:URL"/></dcat:accessURL>
        <!-- xpath: gmd:linkage/gmd:URL -->
        
        <xsl:if test="gmd:name/gco:CharacterString!=''">
          <dct:title><xsl:value-of select=" gmd:name/gco:CharacterString"/></dct:title>
        </xsl:if>
        <!-- xpath: gmd:name/gco:CharacterString -->
        
        <!-- "The size of a distribution.":N/A 
          <dcat:size></dcat:size>
        -->
        
        <xsl:if test="gmd:protocol/gco:CharacterString!=''">
        <dct:format>
          <!-- 
            "the file format of the distribution." 
            
            "MIME type is used for values. A list of MIME types URLs can be found at IANA. 
            However ESRI Shape files have no specific MIME type (A Shape distribution is actually 
            a collection of files), currently this is still an open question?"
            
            In our case, Shapefile will be zipped !
            
            Mapping between protocol list and mime/type when needed
          -->
          <dct:IMT>
            <rdf:value><xsl:value-of select="gmd:protocol/gco:CharacterString"/></rdf:value>
            <rdfs:label><xsl:value-of select="gmd:protocol/gco:CharacterString"/></rdfs:label>
          </dct:IMT>
        </dct:format>
        </xsl:if>
        <!-- xpath: gmd:protocol/gco:CharacterString -->
        
      </dcat:Distribution>
    </xsl:for-each-group>
    
    <xsl:for-each-group select="//gmd:CI_ResponsibleParty[gmd:organisationName/gco:CharacterString!='']" group-by="gmd:organisationName/gco:CharacterString">
      <!-- Organization description. 
        Organization could be linked to a catalogue, a catalogue record.
        
        xpath: //gmd:organisationName
      -->
      <foaf:Organization rdf:about="{$url}/organization/{encode-for-uri(current-grouping-key())}">
        <foaf:name><xsl:value-of select="current-grouping-key()"/></foaf:name>
        <!-- xpath: gmd:organisationName/gco:CharacterString -->
        <xsl:for-each-group select="//gmd:CI_ResponsibleParty[gmd:organisationName/gco:CharacterString=current-grouping-key()]" group-by="gmd:contactInfo/gmd:CI_Contact/gmd:address/gmd:CI_Address/gmd:electronicMailAddress/gco:CharacterString">
          <foaf:member rdf:resource="{$url}/organization/{encode-for-uri(iso19139:getContactId(.))}"/>
        </xsl:for-each-group>
      </foaf:Organization>
    </xsl:for-each-group>
    
    
    <xsl:for-each-group select="//gmd:CI_ResponsibleParty" group-by="gmd:contactInfo/gmd:CI_Contact/gmd:address/gmd:CI_Address/gmd:electronicMailAddress/gco:CharacterString">
      <!-- Organization memeber
        
        xpath: //gmd:CI_ResponsibleParty-->
      
      <foaf:Agent rdf:about="{$url}/person/{encode-for-uri(iso19139:getContactId(.))}">
        <xsl:if test="gmd:individualName/gco:CharacterString">
          <foaf:name><xsl:value-of select="gmd:individualName/gco:CharacterString"/></foaf:name>
        </xsl:if>
        <!-- xpath: gmd:individualName/gco:CharacterString -->
        <xsl:if test="gmd:contactInfo/gmd:CI_Contact/gmd:phone/gmd:CI_Telephone/gmd:voice/gco:CharacterString">
          <foaf:phone><xsl:value-of select="gmd:contactInfo/gmd:CI_Contact/gmd:phone/gmd:CI_Telephone/gmd:voice/gco:CharacterString"/></foaf:phone>
        </xsl:if>
        <!-- xpath: gmd:contactInfo/gmd:CI_Contact/gmd:phone/gmd:CI_Telephone/gmd:voice/gco:CharacterString -->
        <xsl:if test="gmd:contactInfo/gmd:CI_Contact/gmd:address/gmd:CI_Address/gmd:electronicMailAddress/gco:CharacterString">
          <foaf:mbox rdf:resource="mailto:{gmd:contactInfo/gmd:CI_Contact/gmd:address/gmd:CI_Address/gmd:electronicMailAddress/gco:CharacterString}"/>
        </xsl:if>
        <!-- xpath: gmd:contactInfo/gmd:CI_Contact/gmd:address/gmd:CI_Address/gmd:electronicMailAddress/gco:CharacterString -->
      </foaf:Agent>
    </xsl:for-each-group>
  </xsl:template>
  
  
  <!-- Service 
    Create a simple rdf:Description. To be improved.
    
    xpath: //srv:SV_ServiceIdentification||//*[contains(@gco:isoType, 'SV_ServiceIdentification')]
  -->
  <xsl:template match="srv:SV_ServiceIdentification|*[contains(@gco:isoType, 'SV_ServiceIdentification')]" mode="to-dcat">
    <rdf:Description rdf:about="{$url}/resource/{iso19139:getResourceCode(../../.)}">
      <xsl:call-template name="to-dcat-MERIDIAN"/>
    </rdf:Description>
  </xsl:template>
  
  
  
  <!-- Dataset
    "A collection of data, published or curated by a single source, and available for access or 
    download in one or more formats."
    
    xpath: //gmd:MD_DataIdentification|//*[contains(@gco:isoType, 'MD_DataIdentification')]
  -->
  <xsl:template match="gmd:MD_DataIdentification|*[contains(@gco:isoType, 'MD_DataIdentification')]" mode="to-dcat">
    <dcat:Dataset rdf:about="{$url}/resource/{iso19139:getResourceCode(../../.)}">
      <xsl:call-template name="to-dcat-MERIDIAN"/>
    </dcat:Dataset>
  </xsl:template>
  
  
  
  <!-- Build a dcat record for a dataset or service -->
  <xsl:template name="to-dcat-MERIDIAN">
    <!-- "A unique identifier of the dataset." -->
    <dct:identifier><xsl:value-of select="iso19139:getResourceCode(../../.)"/></dct:identifier>
    <!-- xpath: gmd:identificationInfo/*/gmd:citation/*/gmd:identifier/*/gmd:code --> 
    
    
    <dct:title><xsl:value-of select="gmd:citation/*/gmd:title/gco:CharacterString"/></dct:title>
    <!-- xpath: gmd:identificationInfo/*/gmd:citation/*/gmd:title/gco:CharacterString -->
    
    
    <dct:abstract><xsl:value-of select="gmd:abstract/gco:CharacterString"/></dct:abstract>
    <!-- xpath: gmd:identificationInfo/*/gmd:abstract/gco:CharacterString -->
    
    
    <!-- "A keyword or tag describing the dataset."
      Create dcat:keyword if no thesaurus name information available.
    -->
    <xsl:for-each select="gmd:descriptiveKeywords/gmd:MD_Keywords[not(gmd:thesaurusName)]/gmd:keyword/gco:CharacterString">
      <dcat:keyword><xsl:value-of select="."/></dcat:keyword>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:descriptiveKeywords/gmd:MD_Keywords[not(gmd:thesaurusName)]/gmd:keyword/gco:CharacterString --> 
    
    
    <!-- "The main category of the dataset. A dataset can have multiple themes." 
      Create dcat:theme if gmx:Anchor or GEMET concepts or INSPIRE themes
    -->
    <xsl:for-each select="gmd:descriptiveKeywords/gmd:MD_Keywords[(gmd:thesaurusName)]/gmd:keyword/gco:CharacterString">
      <!-- FIXME maybe only do that, if keyword URI is available (when xlink is used ?) -->
      <dcat:theme rdf:resource="{$url}/thesaurus/{iso19139:getThesaurusCode(../../gmd:thesaurusName)}/{.}"/>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:descriptiveKeywords/gmd:MD_Keywords/gmd:keyword/gmx:Anchor --> 
    <!-- xpath: gmd:identificationInfo/*/gmd:descriptiveKeywords/gmd:MD_Keywords/gmd:keyword/gco:CharaceterString -->
    <!-- xpath: gmd:identificationInfo/*/gmd:topicCategory/gmd:MD_TopicCategoryCode -->
    <xsl:for-each select="gmd:topicCategory/gmd:MD_TopicCategoryCode[.!='']">
      <!-- FIXME Is there any public URI pointing to topicCategory enumeration ? -->
      <dcat:theme rdf:resource="{$url}/thesaurus/iso/topicCategory/{.}"/>
    </xsl:for-each>
    
    <!-- Thumbnail -->
    <xsl:for-each select="gmd:graphicOverview/gmd:MD_BrowseGraphic/gmd:fileName/gco:CharacterString">
      <foaf:thumbnail rdf:resource="{.}"/>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:graphicOverview/gmd:MD_BrowseGraphic/gmd:fileName/gco:CharacterString -->
    
    
    <!-- "Spatial coverage of the dataset." -->
    <xsl:for-each select="gmd:extent/*/gmd:geographicElement/gmd:EX_GeographicBoundingBox">
      <xsl:variable name="coords" select="
        concat(gmd:westBoundLongitude/gco:Decimal, ' ', gmd:southBoundLatitude/gco:Decimal),
        concat(gmd:westBoundLongitude/gco:Decimal, ' ', gmd:northBoundLatitude/gco:Decimal),
        concat(gmd:eastBoundLongitude/gco:Decimal, ' ', gmd:northBoundLatitude/gco:Decimal),
        concat(gmd:eastBoundLongitude/gco:Decimal, ' ', gmd:southBoundLatitude/gco:Decimal),
        concat(gmd:westBoundLongitude/gco:Decimal, ' ', gmd:southBoundLatitude/gco:Decimal)
        ">
      </xsl:variable>
      <dct:spatial>
        <ogc:Polygon>
          <ogc:asWKT rdf:datatype="http://www.opengis.net/rdf#WKTLiteral">
            &lt;http://www.opengis.net/def/crs/OGC/1.3/CRS84&gt;
            Polygon((<xsl:value-of select="string-join($coords, ', ')"/>))
          </ogc:asWKT>
        </ogc:Polygon>
      </dct:spatial>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:extent/*/gmd:geographicElement/gmd:EX_GeographicBoundingBox --> 
    
    
    <!-- "The temporal period that the dataset covers." -->
    <!-- TODO could be improved-->
    <xsl:for-each select="gmd:extent/*/gmd:temporalElement/gmd:EX_TemporalExtent/gmd:extent/gml:TimePeriod">
      <dct:temporal>
        <xsl:value-of select="gml:beginPosition"/>
        <xsl:if test="gml:endPosition">
          / <xsl:value-of select="gml:endPosition"/>
        </xsl:if>
      </dct:temporal>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:extent/*/gmd:temporalElement --> 
    
    <xsl:for-each select="gmd:citation/*/gmd:date/gmd:CI_Date[gmd:dateType/gmd:CI_DateTypeCode/@codeListValue='creation']">
      <dct:issued><xsl:value-of select="gmd:date/gco:Date|gmd:date/gco:DateTime"/></dct:issued>
    </xsl:for-each>
    <xsl:for-each select="gmd:citation/*/gmd:date/gmd:CI_Date[gmd:dateType/gmd:CI_DateTypeCode/@codeListValue='revision']">
      <dct:updated><xsl:value-of select="gmd:date/gco:Date|gmd:date/gco:DateTime"/></dct:updated>
    </xsl:for-each>
    
    <!-- "An entity responsible for making the dataset available" -->
    <xsl:for-each select="gmd:pointOfContact/*/gmd:organisationName/gco:CharacterString[.!='']">
      <dct:publisher rdf:resource="{$url}/organization/{encode-for-uri(.)}"/>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:pointOfContact -->
    
    <!-- "The frequency with which dataset is published." See placetime.com intervals. -->
    <xsl:for-each select="gmd:resourceMaintenance/gmd:MD_MaintenanceInformation/gmd:maintenanceAndUpdateFrequency/gmd:MD_MaintenanceFrequencyCode">
      <dct:accrualPeriodicity><xsl:value-of select="@codeListValue"/></dct:accrualPeriodicity>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:resourceMaintenance/gmd:MD_MaintenanceInformation/gmd:maintenanceAndUpdateFrequency/gmd:MD_MaintenanceFrequencyCode/@codeListValue -->
    
    <!-- "This is usually geographical or temporal but can also be other dimension" ??? -->
    <xsl:for-each select="gmd:spatialResolution/gmd:MD_Resolution/gmd:equivalentScale/gmd:MD_RepresentativeFraction/gmd:denominator/gco:Integer[.!='']">
      <dcat:granularity><xsl:value-of select="."/></dcat:granularity>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:spatialResolution/gmd:MD_Resolution/gmd:equivalentScale/gmd:MD_RepresentativeFraction/gmd:denominator/gco:Integer -->
    
    
    <!-- 
      "The language of the dataset."
      "This overrides the value of the catalog language in case of conflict"
    -->
    <xsl:for-each select="gmd:language/gmd:LanguageCode/@codeListValue">
      <dct:language><xsl:value-of select="."/></dct:language>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:language/gmd:LanguageCode/@codeListValue -->
    
    
    <!-- "The license under which the dataset is published and can be reused." -->
    <xsl:for-each select="gmd:resourceConstraints/gmd:MD_LegalConstraints/*/gmd:MD_RestrictionCode">
      <dct:license><xsl:value-of select="@codeListValue"/></dct:license>
    </xsl:for-each>
    <xsl:for-each select="gmd:resourceConstraints/gmd:MD_LegalConstraints/gmd:otherConstraints/gco:CharacterString">
      <dct:license><xsl:value-of select="."/></dct:license>
    </xsl:for-each>
    <!-- xpath: gmd:identificationInfo/*/gmd:resourceConstraints/??? -->
    
    
    <xsl:for-each select="../../gmd:distributionInfo/*/gmd:transferOptions/*/gmd:onLine">
      <dcat:distribution rdf:resource="{gmd:CI_OnlineResource/gmd:linkage/gmd:URL}"/>
    </xsl:for-each>
    <!-- xpath: gmd:distributionInfo/*/gmd:transferOptions/*/gmd:onLine/gmd:CI_OnlineResource -->
    
    
    <!-- ISO19110 relation 
      "This usually consisits of a table providing explanation of columns meaning, values interpretation and acronyms/codes used in the data."
    -->
    <xsl:for-each select="../../gmd:contentInfo/gmd:MD_FeatureCatalogueDescription/gmd:featureCatalogueCitation/@uuidref ">
      <dcat:dataDictionary rdf:resource="{$url}/metadata/{.}"/>
    </xsl:for-each>
    <!-- xpath: gmd:contentInfo/gmd:MD_FeatureCatalogueDescription/gmd:featureCatalogueCitation/@uuidref -->
    
    <!-- Dataset relation
    -->
    <xsl:for-each select="srv:operatesOn/@uuidref ">
      <dct:relation rdf:resource="{$url}/metadata/{.}"/>
    </xsl:for-each>
    
    
    <xsl:for-each select="gmd:aggregationInfo/gmd:MD_AggregateInformation">
      <dct:relation rdf:resource="{$url}/metadata/{gmd:aggregateDataSetIdentifier/gmd:MD_Identifier/gmd:code/gco:CharacterString}"/>
    </xsl:for-each>
    
    <!-- Source relation -->
    <xsl:for-each select="/root/gui/relation/sources/response/metadata">
      <dct:relation rdf:resource="{$url}/metadata/{geonet:info/uuid}"/>
    </xsl:for-each>
    
    
    <!-- Parent/child relation -->
    <xsl:for-each select="../../gmd:parentIdentifier/gco:CharacterString[.!='']">
      <dct:relation rdf:resource="{$url}/metadata/{.}"/>
    </xsl:for-each>
    <xsl:for-each select="/root/gui/relation/children/response/metadata">
      <dct:relation rdf:resource="{$url}/metadata/{geonet:info/uuid}"/>
    </xsl:for-each>
    
    <!-- Service relation -->
    <xsl:for-each select="/root/gui/relations/services/response/metadata">
      <dct:relation rdf:resource="{$url}/metadata/{geonet:info/uuid}"/>
    </xsl:for-each>
    
    
    <!-- 
      "A related document such as technical documentation, agency program page, citation, etc."            
      
      TODO : only for URL ?
      <xsl:for-each select="gmd:citation/*/gmd:otherCitationDetails/gco:CharacterString">
      <dct:reference rdf:resource="url?"/>
      </xsl:for-each>
    -->
    <!-- xpath: gmd:identificationInfo/*/gmd:citation/*/gmd:otherCitationDetails/gco:CharacterString -->
    
    
    <!-- "describes the quality of data." -->
    <xsl:for-each select="../../gmd:dataQualityInfo/*/gmd:lineage/gmd:LI_Lineage/gmd:statement/gco:CharacterString">
      <dcat:dataQuality>
        <!-- rdfs:literal -->
        <xsl:value-of select="."/>
      </dcat:dataQuality>
    </xsl:for-each>
    <!-- xpath: gmd:dataQualityInfo/*/gmd:lineage/gmd:LI_Lineage/gmd:statement/gco:CharacterString -->
    
    
    <!-- FIXME ? 
      <void:dataDump></void:dataDump>-->
  </xsl:template>
  
</xsl:stylesheet>