Fixing GRSF schema

This commit is contained in:
Luca Frosini 2023-03-16 17:38:24 +01:00
parent 12135c09a5
commit 39e3112016
5 changed files with 345 additions and 6 deletions

View File

@ -0,0 +1,85 @@
package org.gcube.grsf.profiles;
import java.io.File;
import java.io.StringReader;
import java.net.URL;
import java.nio.file.Files;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
public class ProfileTest {
private static Logger logger = LoggerFactory.getLogger(ProfileTest.class);
public String fileToString(File file) throws Exception {
try (Stream<String> lines = Files.lines(file.toPath())) {
String content = lines.collect(Collectors.joining(System.lineSeparator()));
return content;
}catch (Exception e) {
throw e;
}
}
public File getResourcesDirectory() throws Exception {
URL logbackFileURL = this.getClass().getClassLoader().getResource("logback-test.xml");
File logbackFile = new File(logbackFileURL.toURI());
File resourcesDirectory = logbackFile.getParentFile();
return resourcesDirectory;
}
public File getProfilesDirectory() throws Exception {
File resourcesDirectory = getResourcesDirectory();
return new File(resourcesDirectory, "profiles");
}
public File getSchemaDirectory() throws Exception {
File resourcesDirectory = getResourcesDirectory();
return new File(resourcesDirectory, "profile_schemas");
}
protected File getSchemaFile() throws Exception {
File schemaDirectory = getSchemaDirectory();
return new File(schemaDirectory, "grsf_profile.xsd");
}
@Test
public void validateAgainstXSD() throws Exception {
File profilesDirectory = getProfilesDirectory();
File schemaFile = getSchemaFile();
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(schemaFile.toURI().toURL());
Validator validator = schema.newValidator();
for(File profileFile : profilesDirectory.listFiles()) {
String xmlString = fileToString(profileFile);
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse( new InputSource(new StringReader(xmlString)));
DOMSource xml = new DOMSource(doc);
try {
validator.validate(xml);
logger.info("File {} has been successfuly validated against schema.", profileFile.getName());
}catch (Exception e) {
logger.error("Error while validating file {}", profileFile.getName());
throw e;
}
}
}
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0}: %msg%n</pattern>
</encoder>
</appender>
<logger name="org.gcube" level="ERROR" />
<logger name="org.gcube.grsf" level="TRACE" />
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -4,7 +4,223 @@
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
vc:minVersion="1.1"> vc:minVersion="1.1">
<xs:redefine schemaLocation="profile5.xsd"> <xs:element name="metadataformat">
<xs:complexType>
<xs:sequence>
<xs:element type="ExtendedMetadataFieldType" name="metadatafield" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute type="NotEmpty" use="required" name="type">
<xs:annotation>
<xs:documentation>
The type (i.e the name) of the profile.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="version" type="xs:integer" use="optional" fixed="5">
<xs:annotation>
<xs:documentation>This XSD is valid for gCube Metadata Profile version 5. Any XML conform to this schema must declare such a version as attibute in the root tag.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:complexType name="TagGroupType">
<xs:sequence>
<xs:choice>
<xs:sequence>
<xs:element name="how" minOccurs="1" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="onFieldName"/>
<xs:enumeration value="onValue"/>
<xs:enumeration value="onFieldName_onValue"/>
<xs:enumeration value="onValue_onFieldName"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:sequence>
<xs:element type="NotEmpty" name="fixedValue" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:choice>
<xs:element name="ifFieldValueMatch" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element type="NotEmpty" name="regex" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:boolean" name="create"/>
</xs:complexType>
<xs:complexType name="TagType">
<xs:complexContent>
<xs:extension base="TagGroupType">
<xs:attribute type="NotEmpty" name="separator" default="_"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="GroupType">
<xs:complexContent>
<xs:extension base="TagGroupType">
<xs:attribute type="xs:boolean" name="propagateUp" default="false"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:simpleType name="NotEmpty">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="MetadataFieldType">
<xs:sequence>
<xs:element type="xs:string" name="fieldId" minOccurs="0">
<xs:annotation>
<xs:documentation>
It declares (if present in the profile) the value that will be used to specify the field name in the Document (e.g. JSON Document) passed to Service that will store the resulting Document. If the 'fieldId' is absent in the profile, the value of the 'fieldName' (which is mandatory) will be used as field name in the Document.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element type="xs:string" name="fieldName">
<xs:annotation>
<xs:documentation>It contains the name of the metadata field.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element type="xs:boolean" name="mandatory" minOccurs="0"
maxOccurs="1">
<xs:annotation>
<xs:documentation>
It declares if the 'metadatafield' is a field mandatory (by using 'true') or not (by using 'false').
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="dataType">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="String"/>
<xs:enumeration value="Time"/>
<xs:enumeration value="Time_Interval"/>
<xs:enumeration value="Times_ListOf"/>
<xs:enumeration value="Text"/>
<xs:enumeration value="Boolean"/>
<xs:enumeration value="Number"/>
<xs:enumeration value="GeoJSON"/>
<xs:enumeration value="File"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element type="xs:string" name="maxOccurs" minOccurs="0"
maxOccurs="1">
<xs:annotation>
<xs:documentation>
It specifies the maximum number of times that the'metadatafield' can occur: N (as number): if the field must appear N times; * (as char asterisk): if the field can appear an unlimited number of times.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element type="xs:string" name="defaultValue" minOccurs="0"
maxOccurs="1"/>
<xs:element type="xs:string" name="note" minOccurs="0" maxOccurs="1"/>
<xs:element name="vocabulary" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="vocabularyField"
minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute type="xs:boolean" name="isMultiSelection"/>
</xs:complexType>
</xs:element>
<xs:element name="validator" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="regularExpression"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:choice>
<xs:element name="tags" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element type="TagType" name="tag" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="tagging" type="TaggingType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
This tagging method is deprecated. Please use the tag 'tags' instead.
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
<xs:choice>
<xs:element name="groups" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element type="GroupType" name="group" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="grouping" type="GroupingType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
This grouping method is deprecated. Please use the tag 'groups' instead.
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
</xs:sequence>
<xs:attribute name="categoryref" use="optional" type="xs:string" />
</xs:complexType>
<xs:complexType name="ExtendedMetadataFieldType">
<xs:complexContent>
<xs:extension base="MetadataFieldType">
<xs:sequence>
<xs:element type="Extra" name="extra" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
Any 'metadataField' definition can include any additional attribute in this 'extra' tag. This tag and its content are ignored by the validators. They are used by any external tools producing/consuming the profile definition and instances.
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Maintain backward compatibility -->
<xs:simpleType name="TaggingGroupingValue">
<xs:restriction base="xs:string">
<xs:enumeration value="onFieldName" />
<xs:enumeration value="onValue" />
<xs:enumeration value="onFieldName_onValue" />
<xs:enumeration value="onValue_onFieldName" />
</xs:restriction>
</xs:simpleType>
<xs:complexType name="TaggingType">
<xs:simpleContent>
<xs:extension base="TaggingGroupingValue">
<xs:attribute type="xs:boolean" name="create" />
<xs:attribute type="NotEmpty" name="separator" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="GroupingType">
<xs:simpleContent id="TaggingGroupingValue">
<xs:extension base="TaggingGroupingValue">
<xs:attribute type="xs:boolean" name="create" />
<xs:attribute type="xs:boolean" name="propagateUp" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="Extra">
<xs:sequence>
<xs:element type="GRSFType" name="grsf" minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
<!-- xs:redefine schemaLocation="profile5.xsd">
<xs:complexType name="Extra"> <xs:complexType name="Extra">
<xs:complexContent> <xs:complexContent>
<xs:extension base="Extra"> <xs:extension base="Extra">
@ -14,12 +230,19 @@
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
</xs:redefine> </xs:redefine -->
<xs:complexType name="GRSFType"> <xs:complexType name="GRSFType">
<xs:sequence> <xs:sequence>
<xs:element type="xs:string" name="srcField" minOccurs="1" maxOccurs="1" /> <xs:element type="xs:string" name="srcField" minOccurs="1" maxOccurs="1" />
<xs:element type="xs:string" name="srcType" minOccurs="1" maxOccurs="1" /> <xs:element type="xs:string" name="srcType" minOccurs="1" maxOccurs="1" />
<xs:element name="containedFields" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element type="FieldType" name="field" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element type="xs:string" name="mandatory" minOccurs="1" maxOccurs="1" /> <xs:element type="xs:string" name="mandatory" minOccurs="1" maxOccurs="1" />
<xs:element type="xs:boolean" name="isSensitive" minOccurs="1" maxOccurs="1" /> <xs:element type="xs:boolean" name="isSensitive" minOccurs="1" maxOccurs="1" />
<xs:element name="dstTypes" minOccurs="1" maxOccurs="1"> <xs:element name="dstTypes" minOccurs="1" maxOccurs="1">
@ -29,6 +252,7 @@
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element type="xs:string" name="comments" minOccurs="0" maxOccurs="1" />
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
@ -48,4 +272,11 @@
</xs:simpleContent> </xs:simpleContent>
</xs:complexType> </xs:complexType>
<xs:complexType name="FieldType">
<xs:sequence>
<xs:element type="xs:string" name="id" minOccurs="1" maxOccurs="1" />
<xs:element type="xs:string" name="type" minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:schema> </xs:schema>

View File

@ -13,7 +13,7 @@
</vocabulary> </vocabulary>
<tags> <tags>
<tag create="true"> <tag create="true">
<how>onFieldValue</how> <how>onValue</how>
</tag> </tag>
</tags> </tags>
<extra> <extra>
@ -227,12 +227,13 @@
<note>A time series of value, unit and date. Example: "catches": [{"unit" : "...", "value": "...", "year": "..."}, ...]</note> <note>A time series of value, unit and date. Example: "catches": [{"unit" : "...", "value": "...", "year": "..."}, ...]</note>
<groups> <groups>
<group create="true" propagateUp="false"> <group create="true" propagateUp="false">
<how>catch-group</how> <fixedValue>catch-group</fixedValue>
</group> </group>
</groups> </groups>
<extra> <extra>
<grsf> <grsf>
<srcField>catches</srcField> <srcField>catches</srcField>
<srcType>ArrayList</srcType>
<mandatory>false</mandatory> <mandatory>false</mandatory>
<isSensitive>true</isSensitive> <isSensitive>true</isSensitive>
<dstTypes> <dstTypes>
@ -250,12 +251,13 @@
<note>A time series of value, unit and date. Example: "landings": [{"unit" : "...", "value": "...", "year": "..."}, ...]</note> <note>A time series of value, unit and date. Example: "landings": [{"unit" : "...", "value": "...", "year": "..."}, ...]</note>
<groups> <groups>
<group create="true" propagateUp="false"> <group create="true" propagateUp="false">
<how>landing-group</how> <fixedValue>landing-group</fixedValue>
</group> </group>
</groups> </groups>
<extra> <extra>
<grsf> <grsf>
<srcField>landings</srcField> <srcField>landings</srcField>
<srcType>ArrayList</srcType>
<mandatory>false</mandatory> <mandatory>false</mandatory>
<isSensitive>true</isSensitive> <isSensitive>true</isSensitive>
<dstTypes> <dstTypes>
@ -265,6 +267,7 @@
</extra> </extra>
</metadatafield> </metadatafield>
<!--
<metadatafield> <metadatafield>
<fieldName></fieldName> <fieldName></fieldName>
<mandatory>false</mandatory> <mandatory>false</mandatory>
@ -301,5 +304,6 @@
</grsf> </grsf>
</extra> </extra>
</metadatafield> </metadatafield>
-->
</metadataformat> </metadataformat>