Skip to content

Commit ca40bb7

Browse files
authored
Stac harvester links to self and items (geonetwork#9082)
* add test * remove 'dead' code * protocol and name for self * add items link * use id as onLine name, use 'STAC Collection' as protocol for 'self'
1 parent f6ef8c7 commit ca40bb7

File tree

5 files changed

+358
-4
lines changed

5 files changed

+358
-4
lines changed

schemas/iso19115-3.2018/src/main/plugin/iso19115-3.2018/convert/stac-to-iso19115-3.xsl

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
<xsl:strip-space elements="*" />
2121

2222
<xsl:template match="/record|*">
23+
<xsl:variable name="id">
24+
<xsl:value-of select="id[1]" />
25+
</xsl:variable>
2326
<mdb:MD_Metadata>
2427
<xsl:call-template name="add-iso19115-3.2018-namespaces" />
2528
<mdb:metadataIdentifier>
@@ -317,11 +320,11 @@
317320
</gco:CharacterString>
318321
</cit:linkage>
319322
<cit:protocol>
320-
<gco:CharacterString>STAC</gco:CharacterString>
323+
<gco:CharacterString>STAC Collection</gco:CharacterString>
321324
</cit:protocol>
322325
<cit:name>
323326
<gco:CharacterString>
324-
<xsl:value-of select="title" />
327+
<xsl:value-of select="$id" />
325328
</gco:CharacterString>
326329
</cit:name>
327330
<cit:description>
@@ -330,6 +333,28 @@
330333
</cit:CI_OnlineResource>
331334
</mrd:onLine>
332335
</xsl:for-each>
336+
<xsl:for-each select="links[rel = 'items']">
337+
<mrd:onLine>
338+
<cit:CI_OnlineResource>
339+
<cit:linkage>
340+
<gco:CharacterString>
341+
<xsl:value-of select="href" />
342+
</gco:CharacterString>
343+
</cit:linkage>
344+
<cit:protocol>
345+
<gco:CharacterString>STAC Items</gco:CharacterString>
346+
</cit:protocol>
347+
<cit:name>
348+
<gco:CharacterString>
349+
<xsl:value-of select="$id" />
350+
</gco:CharacterString>
351+
</cit:name>
352+
<cit:description>
353+
<gco:CharacterString>STAC Items</gco:CharacterString>
354+
</cit:description>
355+
</cit:CI_OnlineResource>
356+
</mrd:onLine>
357+
</xsl:for-each>
333358
</mrd:MD_DigitalTransferOptions>
334359
</mrd:transferOptions>
335360
</mrd:MD_Distribution>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (C) 2001-2025 Food and Agriculture Organization of the
3+
* United Nations (FAO-UN), United Nations World Food Programme (WFP)
4+
* and United Nations Environment Programme (UNEP)
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or (at
9+
* your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful, but
12+
* WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19+
*
20+
* Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
21+
* Rome - Italy. email: [email protected]
22+
*/
23+
24+
package org.fao.geonet.schema;
25+
26+
import org.fao.geonet.utils.TransformerFactoryFactory;
27+
import org.fao.geonet.utils.Xml;
28+
import org.jdom.Document;
29+
import org.jdom.Element;
30+
import org.jdom.output.Format;
31+
import org.jdom.output.XMLOutputter;
32+
import org.jdom.xpath.XPath;
33+
import org.junit.BeforeClass;
34+
import org.junit.Test;
35+
36+
import java.nio.file.Path;
37+
38+
import static org.fao.geonet.schema.TestSupport.getResource;
39+
import static org.fao.geonet.schema.TestSupport.getResourceInsideSchema;
40+
41+
public class StacConversionTest {
42+
43+
private static final boolean GENERATE_EXPECTED_FILE = false;
44+
45+
@BeforeClass
46+
public static void initSaxon() {
47+
TransformerFactoryFactory.init("net.sf.saxon.TransformerFactoryImpl");
48+
}
49+
50+
@Test
51+
public void sentinel2RadiometricIndices() throws Exception {
52+
transformAndCompare("convert/stac-to-iso19115-3.xsl", "sentinel-2-radiometric-indices-input.xml", "sentinel-2-radiometric-indices-output.xml");
53+
}
54+
55+
private void transformAndCompare(String scriptName, String inputFileName, String expectedFileName) throws Exception {
56+
Path xslFile = getResourceInsideSchema(scriptName);
57+
Path xmlFile = getResource("stacHarvester/" + inputFileName);
58+
Element md = Xml.loadFile(xmlFile);
59+
60+
Element mdIso19115_3 = Xml.transform(md, xslFile);
61+
62+
XPath xPath = XPath.newInstance(".//mdb:dateInfo/cit:CI_Date/cit:date/gco:DateTime");
63+
((Element)xPath.selectNodes(mdIso19115_3).get(0)).setText("2025-10-23T13:41:06.565+02:00");
64+
65+
XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat().setLineSeparator("\n"));
66+
String actual = xmlOutputter.outputString(new Document(mdIso19115_3));
67+
TestSupport.assertGeneratedDataByteMatchExpected("stacHarvester/" + expectedFileName, actual, GENERATE_EXPECTED_FILE);
68+
}
69+
70+
}

schemas/iso19115-3.2018/src/test/java/org/fao/geonet/schema/ToIsoKeywordTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ private void transformAndCompare(String scriptName, String inputFileName, String
6060

6161
XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat().setLineSeparator("\n"));
6262
String actual = xmlOutputter.outputString(new Document(cswRecord));
63-
boolean generateExpectedFileNameOnlyIfInputDiffersFromExpected = GENERATE_EXPECTED_FILE && !expectedFileName.equals(inputFileName);
64-
TestSupport.assertGeneratedDataByteMatchExpected(expectedFileName, actual, generateExpectedFileNameOnlyIfInputDiffersFromExpected);
63+
TestSupport.assertGeneratedDataByteMatchExpected(expectedFileName, actual, GENERATE_EXPECTED_FILE);
6564
}
6665

6766
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<record>
3+
<extent>
4+
<spatial>
5+
<bbox>
6+
<array>-5.719358444214</array>
7+
<array>41.456241607666</array>
8+
<array>10.354447364807</array>
9+
<array>51.451183319092</array>
10+
</bbox>
11+
</spatial>
12+
<temporal>
13+
<interval>
14+
<array>2015-07-04T10:18:58.537000Z</array>
15+
<array>2025-10-11T10:59:35.504000Z</array>
16+
</interval>
17+
</temporal>
18+
</extent>
19+
<license>CC-BY-SA</license>
20+
<stac_version>1.1.0</stac_version>
21+
<assets>
22+
<ql>
23+
<roles>thumbnail</roles>
24+
<href>https://i.ibb.co/jkp9zxC/sentinel-2-indices-quicklook.png</href>
25+
<type>image/png</type>
26+
<title>Rendered preview</title>
27+
</ql>
28+
</assets>
29+
<description>Radiometric indices computed from THEIA's sentinel-2 Level 2A images</description>
30+
<links>
31+
<rel>items</rel>
32+
<href>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections/sentinel-2-radiometric-indices/items</href>
33+
<type>application/geo+json</type>
34+
</links>
35+
<links>
36+
<rel>parent</rel>
37+
<href>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/</href>
38+
<type>application/json</type>
39+
</links>
40+
<links>
41+
<rel>root</rel>
42+
<href>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/</href>
43+
<type>application/json</type>
44+
</links>
45+
<links>
46+
<rel>self</rel>
47+
<href>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections/sentinel-2-radiometric-indices</href>
48+
<type>application/json</type>
49+
</links>
50+
<links>
51+
<rel>http://www.opengis.net/def/rel/ogc/1.0/queryables</rel>
52+
<href>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections/sentinel-2-radiometric-indices/queryables</href>
53+
<type>application/schema+json</type>
54+
<title>Queryables</title>
55+
</links>
56+
<id>sentinel-2-radiometric-indices</id>
57+
<type>Collection</type>
58+
<title>Sentinel-2 Level 2A radiometric indices</title>
59+
<stac_extensions>https://forge.inrae.fr/teledec/stac-extensions/schemas/-/raw/main/production/v1.1.0/schema.json</stac_extensions>
60+
<stac_extensions>https://stac-extensions.github.io/projection/v2.0.0/schema.json</stac_extensions>
61+
<stac_extensions>https://stac-extensions.github.io/raster/v1.1.0/schema.json</stac_extensions>
62+
<stac_extensions>https://stac-extensions.github.io/eo/v1.1.0/schema.json</stac_extensions>
63+
<stac_extensions>https://stac-extensions.github.io/sentinel-2/v1.0.0/schema.json</stac_extensions>
64+
<stac_extensions>https://stac-extensions.github.io/contacts/v0.1.1/schema.json</stac_extensions>
65+
<contacts>
66+
<organization>INRAE</organization>
67+
<name>Rémi Cresson</name>
68+
</contacts>
69+
<uuid>sentinel-2-radiometric-indices</uuid>
70+
<apiUrl>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections</apiUrl>
71+
<nodeUrl>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr</nodeUrl>
72+
</record>
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<mdb:MD_Metadata xmlns:mdb="http://standards.iso.org/iso/19115/-3/mdb/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cat="http://standards.iso.org/iso/19115/-3/cat/1.0" xmlns:gfc="http://standards.iso.org/iso/19110/gfc/1.1" xmlns:cit="http://standards.iso.org/iso/19115/-3/cit/2.0" xmlns:gcx="http://standards.iso.org/iso/19115/-3/gcx/1.0" xmlns:gex="http://standards.iso.org/iso/19115/-3/gex/1.0" xmlns:lan="http://standards.iso.org/iso/19115/-3/lan/1.0" xmlns:srv="http://standards.iso.org/iso/19115/-3/srv/2.0" xmlns:mas="http://standards.iso.org/iso/19115/-3/mas/1.0" xmlns:mcc="http://standards.iso.org/iso/19115/-3/mcc/1.0" xmlns:mco="http://standards.iso.org/iso/19115/-3/mco/1.0" xmlns:mda="http://standards.iso.org/iso/19115/-3/mda/1.0" xmlns:mds="http://standards.iso.org/iso/19115/-3/mds/2.0" xmlns:mdt="http://standards.iso.org/iso/19115/-3/mdt/2.0" xmlns:mex="http://standards.iso.org/iso/19115/-3/mex/1.0" xmlns:mmi="http://standards.iso.org/iso/19115/-3/mmi/1.0" xmlns:mpc="http://standards.iso.org/iso/19115/-3/mpc/1.0" xmlns:mrc="http://standards.iso.org/iso/19115/-3/mrc/2.0" xmlns:mrd="http://standards.iso.org/iso/19115/-3/mrd/1.0" xmlns:mri="http://standards.iso.org/iso/19115/-3/mri/1.0" xmlns:mrl="http://standards.iso.org/iso/19115/-3/mrl/2.0" xmlns:mrs="http://standards.iso.org/iso/19115/-3/mrs/1.0" xmlns:msr="http://standards.iso.org/iso/19115/-3/msr/2.0" xmlns:mdq="http://standards.iso.org/iso/19157/-2/mdq/1.0" xmlns:dqm="http://standards.iso.org/iso/19157/-2/dqm/1.0" xmlns:mac="http://standards.iso.org/iso/19115/-3/mac/2.0" xmlns:gco="http://standards.iso.org/iso/19115/-3/gco/1.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xlink="http://www.w3.org/1999/xlink">
3+
<mdb:metadataIdentifier>
4+
<mcc:MD_Identifier>
5+
<mcc:code>
6+
<gco:CharacterString>sentinel-2-radiometric-indices</gco:CharacterString>
7+
</mcc:code>
8+
</mcc:MD_Identifier>
9+
</mdb:metadataIdentifier>
10+
<mdb:defaultLocale>
11+
<lan:PT_Locale>
12+
<lan:language>
13+
<lan:LanguageCode codeList="codeListLocation#LanguageCode" codeListValue="fre" />
14+
</lan:language>
15+
<lan:characterEncoding>
16+
<lan:MD_CharacterSetCode codeList="codeListLocation#MD_CharacterSetCode" codeListValue="utf8" />
17+
</lan:characterEncoding>
18+
</lan:PT_Locale>
19+
</mdb:defaultLocale>
20+
<mdb:metadataScope>
21+
<mdb:MD_MetadataScope>
22+
<mdb:resourceScope>
23+
<mcc:MD_ScopeCode codeList="http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#MD_ScopeCode" codeListValue="series" />
24+
</mdb:resourceScope>
25+
<mdb:name>
26+
<gco:CharacterString>Data collection</gco:CharacterString>
27+
</mdb:name>
28+
</mdb:MD_MetadataScope>
29+
</mdb:metadataScope>
30+
<mdb:contact>
31+
<cit:CI_Responsibility>
32+
<cit:role>
33+
<cit:CI_RoleCode codeList="codeListLocation#CI_RoleCode" codeListValue="pointOfContact" />
34+
</cit:role>
35+
<cit:party>
36+
<cit:CI_Organisation>
37+
<cit:name>
38+
<gco:CharacterString>INRAE</gco:CharacterString>
39+
</cit:name>
40+
<cit:contactInfo>
41+
<cit:CI_Contact />
42+
</cit:contactInfo>
43+
<cit:individual>
44+
<cit:CI_Individual>
45+
<cit:name>
46+
<gco:CharacterString>Rémi Cresson</gco:CharacterString>
47+
</cit:name>
48+
</cit:CI_Individual>
49+
</cit:individual>
50+
</cit:CI_Organisation>
51+
</cit:party>
52+
</cit:CI_Responsibility>
53+
</mdb:contact>
54+
<mdb:dateInfo>
55+
<cit:CI_Date>
56+
<cit:date>
57+
<gco:DateTime>2025-10-23T13:41:06.565+02:00</gco:DateTime>
58+
</cit:date>
59+
<cit:dateType>
60+
<cit:CI_DateTypeCode codeList="http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#CI_DateTypeCode" codeListValue="creation" />
61+
</cit:dateType>
62+
</cit:CI_Date>
63+
</mdb:dateInfo>
64+
<mdb:identificationInfo>
65+
<mri:MD_DataIdentification>
66+
<mri:citation>
67+
<cit:CI_Citation>
68+
<cit:title>
69+
<gco:CharacterString>Sentinel-2 Level 2A radiometric indices</gco:CharacterString>
70+
</cit:title>
71+
</cit:CI_Citation>
72+
</mri:citation>
73+
<mri:abstract>
74+
<gco:CharacterString>Radiometric indices computed from THEIA's sentinel-2 Level 2A images</gco:CharacterString>
75+
</mri:abstract>
76+
<mri:topicCategory>
77+
<mri:MD_TopicCategoryCode>imageryBaseMapsEarthCover</mri:MD_TopicCategoryCode>
78+
</mri:topicCategory>
79+
<mri:extent>
80+
<gex:EX_Extent>
81+
<gex:geographicElement>
82+
<gex:EX_GeographicBoundingBox>
83+
<gex:westBoundLongitude>
84+
<gco:Decimal>-5.719358444214</gco:Decimal>
85+
</gex:westBoundLongitude>
86+
<gex:eastBoundLongitude>
87+
<gco:Decimal>10.354447364807</gco:Decimal>
88+
</gex:eastBoundLongitude>
89+
<gex:southBoundLatitude>
90+
<gco:Decimal>41.456241607666</gco:Decimal>
91+
</gex:southBoundLatitude>
92+
<gex:northBoundLatitude>
93+
<gco:Decimal>51.451183319092</gco:Decimal>
94+
</gex:northBoundLatitude>
95+
</gex:EX_GeographicBoundingBox>
96+
</gex:geographicElement>
97+
<gex:temporalElement>
98+
<gex:EX_TemporalExtent>
99+
<gex:extent>
100+
<gml:TimePeriod>
101+
<gml:beginPosition>2015-07-04T10:18:58.537000Z</gml:beginPosition>
102+
<gml:endPosition>2025-10-11T10:59:35.504000Z</gml:endPosition>
103+
</gml:TimePeriod>
104+
</gex:extent>
105+
</gex:EX_TemporalExtent>
106+
</gex:temporalElement>
107+
</gex:EX_Extent>
108+
</mri:extent>
109+
<mri:graphicOverview>
110+
<mcc:MD_BrowseGraphic>
111+
<mcc:fileName>
112+
<gco:CharacterString>https://i.ibb.co/jkp9zxC/sentinel-2-indices-quicklook.png</gco:CharacterString>
113+
</mcc:fileName>
114+
<mcc:fileDescription>
115+
<gco:CharacterString>Rendered preview</gco:CharacterString>
116+
</mcc:fileDescription>
117+
<mcc:fileType>
118+
<gco:CharacterString>image/png</gco:CharacterString>
119+
</mcc:fileType>
120+
</mcc:MD_BrowseGraphic>
121+
</mri:graphicOverview>
122+
<mri:resourceConstraints>
123+
<mco:MD_LegalConstraints>
124+
<mco:accessConstraints>
125+
<mco:MD_RestrictionCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_RestrictionCode" codeListValue="license" />
126+
</mco:accessConstraints>
127+
<mco:accessConstraints>
128+
<mco:MD_RestrictionCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_RestrictionCode" codeListValue="otherRestrictions" />
129+
</mco:accessConstraints>
130+
<mco:otherConstraints>
131+
<gco:CharacterString>CC-BY-SA</gco:CharacterString>
132+
</mco:otherConstraints>
133+
</mco:MD_LegalConstraints>
134+
</mri:resourceConstraints>
135+
<mri:defaultLocale>
136+
<lan:PT_Locale>
137+
<lan:language>
138+
<lan:LanguageCode codeList="codeListLocation#LanguageCode" codeListValue="fre" />
139+
</lan:language>
140+
<lan:characterEncoding>
141+
<lan:MD_CharacterSetCode codeList="codeListLocation#MD_CharacterSetCode" codeListValue="utf8" />
142+
</lan:characterEncoding>
143+
</lan:PT_Locale>
144+
</mri:defaultLocale>
145+
</mri:MD_DataIdentification>
146+
</mdb:identificationInfo>
147+
<mdb:distributionInfo>
148+
<mrd:MD_Distribution>
149+
<mrd:transferOptions>
150+
<mrd:MD_DigitalTransferOptions>
151+
<mrd:onLine>
152+
<cit:CI_OnlineResource>
153+
<cit:linkage>
154+
<gco:CharacterString>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections/sentinel-2-radiometric-indices</gco:CharacterString>
155+
</cit:linkage>
156+
<cit:protocol>
157+
<gco:CharacterString>STAC Collection</gco:CharacterString>
158+
</cit:protocol>
159+
<cit:name>
160+
<gco:CharacterString>sentinel-2-radiometric-indices</gco:CharacterString>
161+
</cit:name>
162+
<cit:description>
163+
<gco:CharacterString>STAC Collection</gco:CharacterString>
164+
</cit:description>
165+
</cit:CI_OnlineResource>
166+
</mrd:onLine>
167+
<mrd:onLine>
168+
<cit:CI_OnlineResource>
169+
<cit:linkage>
170+
<gco:CharacterString>https://stacapi-cdos.apps.okd.crocc.meso.umontpellier.fr/collections/sentinel-2-radiometric-indices/items</gco:CharacterString>
171+
</cit:linkage>
172+
<cit:protocol>
173+
<gco:CharacterString>STAC Items</gco:CharacterString>
174+
</cit:protocol>
175+
<cit:name>
176+
<gco:CharacterString>sentinel-2-radiometric-indices</gco:CharacterString>
177+
</cit:name>
178+
<cit:description>
179+
<gco:CharacterString>STAC Items</gco:CharacterString>
180+
</cit:description>
181+
</cit:CI_OnlineResource>
182+
</mrd:onLine>
183+
</mrd:MD_DigitalTransferOptions>
184+
</mrd:transferOptions>
185+
</mrd:MD_Distribution>
186+
</mdb:distributionInfo>
187+
</mdb:MD_Metadata>
188+

0 commit comments

Comments
 (0)