diff --git a/src/app/datasets/datasets.component.html b/src/app/datasets/datasets.component.html index 60124271d03c2e0e8d2da7c5718781eca10492f7..5fdfcf3a1c98e803c8a4ad6a21e556417f16c2f1 100644 --- a/src/app/datasets/datasets.component.html +++ b/src/app/datasets/datasets.component.html @@ -41,7 +41,7 @@ <ng-template #preview> <ng-container *ngIf="request.tags != null && request.tags.length > 0"> <pre *ngIf="request.tags[0] === tagEnum.dataset && openApi.info['x-result'] === 'xml' ">{{ previews.get(path.pathName) }}</pre> - <pre *ngIf="request.tags[0] === tagEnum.dataset && openApi.info['x-result'] === 'json' ">{{ previews.get(path.pathName) | json }}</pre> + <pre *ngIf="request.tags[0] === tagEnum.dataset && openApi.info['x-result'] !== 'xml' ">{{ previews.get(path.pathName) | json }}</pre> <ul *ngIf="request.tags[0] === tagEnum.search"> <li *ngFor="let datasetId of previews.get(path.pathName)">{{datasetId}}</li> </ul> diff --git a/src/app/datasets/datasets.component.ts b/src/app/datasets/datasets.component.ts index 35ac999ec6c54757720b6a5caab6a66da2d2f894..a730d01c11fad46f205cc8ed90539f3cdb744890 100644 --- a/src/app/datasets/datasets.component.ts +++ b/src/app/datasets/datasets.component.ts @@ -204,7 +204,7 @@ export class DatasetsComponent implements OnInit, AfterViewChecked, AfterContent getRequestPromiseByHttpMethod(httpMethod: HttpMethod, requestUrl: string, headers: any, pathName: string): Promise<any> { let requestObs: Observable<any>; - + console.log(this.openApi.info['x-result'] === "xml") switch (httpMethod.toLowerCase()) { case HttpMethod.GET: diff --git a/src/app/datasets/services/dataset-crud.service.ts b/src/app/datasets/services/dataset-crud.service.ts index 70b4b6747d5d6c0e9a9c2126c52b4a1610c1211e..5501eeb689749f80c38812c5417e19a5a7cbda17 100644 --- a/src/app/datasets/services/dataset-crud.service.ts +++ b/src/app/datasets/services/dataset-crud.service.ts @@ -78,6 +78,7 @@ export class DatasetCrudService { } } + draftDataset(url: string) { if (this.fds2Token) { const httpOptions = { @@ -104,7 +105,7 @@ export class DatasetCrudService { } } - createDistribution(data: string) { + createDistribution(data: string): Observable<Object> { if (this.fds2Token) { const httpOptions = { @@ -115,10 +116,7 @@ export class DatasetCrudService { }) }; - const resultat = this.http.post(FDP_URL + '/distribution', data, httpOptions).subscribe((r) => { - console.log('reponse: ', r); - return JSON.stringify(resultat); - }); + return this.http.post(FDP_URL + '/distribution', data, httpOptions); } } diff --git a/src/app/mapping/class/dataset.ts b/src/app/mapping/class/dataset.ts index 526b7b76959fa15e87f6d77531fcffb181fe3cbf..d1834ce91a0ae4b4b0e9a2aad546eef1fee60abf 100644 --- a/src/app/mapping/class/dataset.ts +++ b/src/app/mapping/class/dataset.ts @@ -1,25 +1,68 @@ -export class Dataset { +export class Property { + public property: string; + public uri: string; + public usageNote: string; + public range?: string; + public card: string; + public geodcat: boolean; + public isDuplicated?: boolean = false; + public dcatClass?: string; + + constructor(name: string, identifier: string, usageNote: string, isDuplicated: boolean, card: string, geodcat:boolean) { + this.property = name; + this.uri = identifier; + this.usageNote = usageNote; + this.isDuplicated = isDuplicated; + this.card = card; + this.geodcat = geodcat; + } +} + + +export class OldProperty { public name: string; public identifier: string; public usageNote: string; - public isDuplicated: boolean; - - constructor(name: string, identifier: string, usageNote: string, isDuplicated: boolean) { + public isDuplicated?: boolean = false; + + constructor(name: string, identifier: string, usageNote: string, isDuplicated: boolean, card: string, geodcat:boolean) { this.name = name; this.identifier = identifier; this.usageNote = usageNote; this.isDuplicated = isDuplicated; + } } - export class DatasetPath { - public dcatProperty: Dataset | string; - public path: string + public dcatProperty: Property | string; + public path: string; + public dcatClass: string; - constructor(dcatProperty: Dataset, path: string) { + constructor(dcatProperty: Property, path: string, dcatClass: string) { this.dcatProperty = dcatProperty; this.path = path; + this.dcatClass = dcatClass; } } +export class Distribution { + public property: string; + public uri: string; + public range: string; + public usageNote: string; + public card: string; + public geodcat: boolean; + public isDuplicated?: boolean = false; + + +} + +export class ResponseFileTsv { + public subject_label: string; + public predicat_id: string; + public object_id: string; + public match_type: string; + public object_category: string; +} + diff --git a/src/app/mapping/class/stringUtils.ts b/src/app/mapping/class/stringUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6516a1a0ebd87a6e7c03eff9bb1fafb2a24e938 --- /dev/null +++ b/src/app/mapping/class/stringUtils.ts @@ -0,0 +1,33 @@ +export class StringUtils { + + trimPropertyName(value) { + return value.replace(/\s/g, ''); + } + + getValueFormatByType(value) { + if(value === undefined || value === ''){ + return String(); + } + //is Number + let isNumber = !isNaN(value); + if (isNumber) { + return Number(value); + } + // is Boolean + if(value === "true" || value === "false"){ + return JSON.parse(value.toLowerCase()); + } + return String(value); + } + + hasContent(values) { + if (values.length > 0) { + for (let i = 0; i < values.length; i++) { + if (values[i]) { + return true; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/src/app/mapping/mapping.component.html b/src/app/mapping/mapping.component.html index 247491b876a471242609fa605c69b58dd663af63..bcc97e8562041c5e4c4118d6b983a38b58527185 100644 --- a/src/app/mapping/mapping.component.html +++ b/src/app/mapping/mapping.component.html @@ -9,35 +9,36 @@ </nb-card-body> </nb-card> + <form #form="ngForm" *ngIf="ontology"> + <div class="row"> + <p>Upload Or fill out the form with the path corresponding to the dcat property and save a + new + file for next mappings:</p> + <button class="button-center" nbButton status="primary" (click)="openFileInputDialog()"> + <nb-icon icon="upload-outline"></nb-icon>Import file + </button> + <input type="file" id="file" (change)="importJson($event)" accept=".json, .tsv" /> + </div> <div class="card-row"> <div class="card-col"> <nb-card size="giant"> - <nb-card-header>Dataset metadata</nb-card-header> + <nb-card-header>Dataset</nb-card-header> <nb-card-body> - <div class="row"> - <p>Upload Or fill out the form with the path corresponding to the dcat property and save a - new - file for next mappings:</p> - <button class="button-center" nbButton status="primary" (click)="openFileInputDialog()"> - <nb-icon icon="upload-outline"></nb-icon>Import file - </button> - <input type="file" id="file" (change)="importJson($event)" accept=".json" /> - </div> + - <ng-container - *ngFor="let dataset of dcatVocabulary ; let index = index"> + <ng-container *ngFor="let dataset of datasets ; let index = index; trackBy: trackByIndex"> <nb-form-field> <div class="row"> <div class="col-3" style="margin-right: 10px;"> <nb-form-field> - <input *ngIf=" dataset.identifier !== 'dct:title'" nbInput fullWidth - type="text" value="{{dataset.identifier}} " disabled /> - <input *ngIf=" dataset.identifier === 'dct:title' " nbInput fullWidth - type="text" value="{{dataset.identifier}} *" disabled /> - <button nbSuffix nbTooltip="{{dataset.name}}: {{dataset.usageNote}}" + <input *ngIf="!isMandatory(dataset.card)" nbInput fullWidth type="text" + value="{{dataset.uri}} " disabled style="color: black;" /> + <input *ngIf="isMandatory(dataset.card)" nbInput fullWidth type="text" + value="{{dataset.uri}} *" disabled style="color: black;" /> + <button nbSuffix nbTooltip="{{dataset.property}}: {{dataset.usageNote}}" nbTooltipStatus="info" nbButton status="basic" ghost> <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva"> </nb-icon> @@ -48,23 +49,14 @@ <div class="col-7"> <nb-form-field> - <input - *ngIf=" dataset.identifier === 'dct:title' " - required fullWidth - name=" {{index}}" nbInput - (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto" - [(ngModel)]="selectedPaths[index]" - (focus)="reset()"/> - <div - *ngIf="dataset.identifier.invalid && (dataset.identifier.dirty || dataset.identifier.touched)"> - champ obligatoire</div> - <input - *ngIf=" dataset.identifier !== 'dct:title'" - fullWidth - name=" {{index}}" nbInput - (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto" - [(ngModel)]="selectedPaths[index]" - (focus)="reset()"/> + <input *ngIf="isMandatory(dataset.card)" required fullWidth + name=" data{{index}}" nbInput (ngModelChange)="onModelChange($event)" + [nbAutocomplete]="auto" [(ngModel)]="selectedPaths[index]" [value]="selectedPaths[index]? selectedPaths[index] : ''" + (focus)="reset()" /> + + <input *ngIf="!isMandatory(dataset.card)" fullWidth name=" data{{index}}" + nbInput (ngModelChange)="onModelChange($event)" [nbAutocomplete]="auto" + [(ngModel)]="selectedPaths[index]" [value]="selectedPaths[index]? selectedPaths[index] : ''" (focus)="reset()" /> <nb-autocomplete #auto> @@ -76,14 +68,90 @@ </nb-autocomplete> </nb-form-field> </div> - <div class="col-2" *ngIf="isMultiple(dataset.identifier)" + <div class="col-2" *ngIf="isReplicable(dataset.card) " style="margin-left: 10px;"> + <button nbButton ghost (click)="addField(index, datasets, selectedPaths)" *ngIf="dataset.uri !== datasets[index - 1].uri"> + <nb-icon icon="plus-outline" status="primary"> + </nb-icon> + </button> + <button nbButton ghost *ngIf="dataset.uri === datasets[index - 1].uri" + (click)="deleteField(index, datasets, selectedPaths)"> + <nb-icon icon="trash-2-outline" status="danger"> + </nb-icon> + </button> + </div> + </div> + </nb-form-field> + </ng-container> + + </nb-card-body> + </nb-card> + </div> + </div> + <div class="car-col"> + <nb-card> + <nb-card-body> + <nb-checkbox (checkedChange)="toggleDistri($event)">Add a distribution</nb-checkbox> + </nb-card-body> + </nb-card> + </div> + <div class="card-row" *ngIf="addDistribution"> + <div class="card-col"> + <nb-card size="giant"> + <nb-card-header>Distribution</nb-card-header> + <nb-card-body> + <ng-container *ngFor="let distribution of distributions; let index = index; trackBy: trackByIndex" > + <nb-form-field> + <div class="row"> + + <div class="col-3" style="margin-right: 10px;"> + + <nb-form-field> + <input *ngIf="!isMandatory(distribution.card)" nbInput fullWidth type="text" + value="{{distribution.uri}} " disabled style="color: black;" /> + <input *ngIf="isMandatory(distribution.card)" nbInput fullWidth type="text" + value="{{distribution.uri}} *" disabled style="color: black;" /> + <button nbSuffix + nbTooltip="{{distribution.property}}: {{distribution.usageNote}}" + nbTooltipStatus="info" nbButton status="basic" ghost> + <nb-icon [icon]=" 'question-mark-circle-outline' " pack="eva"> + </nb-icon> + </button> + </nb-form-field> + + </div> + <div class="col-7"> + + <nb-form-field> + <input *ngIf="isMandatory(distribution.card)" required fullWidth + name=" distri{{index}}" nbInput (ngModelChange)="onModelChange($event)" + [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]" [value]="distributionSelectedPaths[index]? distributionSelectedPaths[index] : ''" + (focus)="reset()" /> + + <input *ngIf="!isMandatory(distribution.card)" fullWidth + name=" distri{{index}}" nbInput (ngModelChange)="onModelChange($event)" + [nbAutocomplete]="auto" [(ngModel)]="distributionSelectedPaths[index]" + [value]="distributionSelectedPaths[index]? distributionSelectedPaths[index] : ''" + (focus)="reset()" /> + + <nb-autocomplete #auto> + + <nb-option *ngFor="let option of filteredOptions | async" + [value]="option"> + {{ option }} + </nb-option> + + </nb-autocomplete> + </nb-form-field> + </div> + <div class="col-2" *ngIf="isReplicable(distribution.card)" style="margin-left: 10px;"> - <button nbButton ghost (click)="addField(index)" *ngIf="!dataset.isDuplicated"> + <button nbButton ghost (click)="addField(index, distributions, distributionSelectedPaths)" + *ngIf="distribution.uri !== distributions[index - 1].uri"> <nb-icon icon="plus-outline" status="primary"> </nb-icon> </button> - <button nbButton ghost *ngIf="dataset.isDuplicated" - (click)="deleteField(index)"> + <button nbButton ghost *ngIf="distribution.uri === distributions[index - 1].uri" + (click)="deleteField(index, distributions, distributionSelectedPaths)"> <nb-icon icon="trash-2-outline" status="danger"> </nb-icon> </button> @@ -100,69 +168,127 @@ <button class="button-center" nbButton status="primary" (click)="downloadJson()">Save locally</button> </div> <div class="row"> - <button class="button-center" nbButton status="primary" (click)="mapDataset()" + <button class="button-center" nbButton status="primary" (click)="mapDataset(); check = true" [disabled]="!form.valid">Check mapping</button> </div> </form> - <div class="card-row"> + <div class="card-row" *ngIf="check"> <div class="card-col"> <nb-card [nbSpinner]="loadingCr" nbSpinnerStatus="primary" nbSpinnerSize="giant" nbSpinnerMessage="loading"> - <nb-card-header>Map</nb-card-header> + <nb-card-body> - <nb-list> + <nb-card> + <nb-card-header>Dataset</nb-card-header> - <nb-list-item *ngFor="let data of mappedMetadatas[index] | keyvalue; trackBy:trackByIndex; "> - <div class="row"> - <div class="col-3"><label - for="{{data.key}}">{{dcatVocabulary[data.key].identifier}}</label> - </div> - <div class="col-7"> - <ng-template #normal> - <input nbInput [ngModel]="data.value" - (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" /> - </ng-template> - <ng-container - *ngIf="isArray(data.value) && !isMultiple(dcatVocabulary[data.key].identifier); else normal"> - <input nbInput [ngModel]="data.value[0]" - (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" /> - </ng-container> - <ng-container - *ngIf="isArray(data.value) && isMultiple(dcatVocabulary[data.key].identifier)"> - <ul *ngFor="let val of data.value" style="margin-left: -100px;"> - <li> - <div class="row"> - <div class="col-3"> - <label - for="{{data.key}}">{{dcatVocabulary[data.key].identifier}}</label> - </div> - <div class="col-7"> - <input nbInput [ngModel]="val" - (ngModelChange)="mappedMetadatas[index].set(data.key, $event)" /> - </div> - <div class="col-2"> + <nb-list> + <nb-list-item + *ngFor="let data of datasetMappedMetadatas[index] | keyvalue; trackBy:trackByIndex; "> + <div class="row"> + <div class="col-3"><label + for="{{data.key}}">{{datasets[data.key].uri}}</label> + </div> + <div class="col-7"> + <ng-template #normal> + <input nbInput [ngModel]="data.value" + (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" /> + </ng-template> + <ng-container + *ngIf="isArray(data.value) && !isReplicable(datasets[data.key].card); else normal"> + <input nbInput [ngModel]="data.value[0]" + (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" /> + </ng-container> + <ng-container + *ngIf="isArray(data.value) && isReplicable(datasets[data.key].card)"> + <ul *ngFor="let val of data.value" style="margin-left: -100px;"> + <li> + <div class="row"> + <div class="col-3"> + <label + for="{{data.key}}">{{datasets[data.key].uri}}</label> + </div> + <div class="col-7"> + <input nbInput [ngModel]="val" + (ngModelChange)="datasetMappedMetadatas[index].set(data.key, $event)" /> + </div> + <div class="col-2"> + </div> </div> - </div> - </li> - </ul> - </ng-container> + </li> + </ul> + </ng-container> + </div> + <div class="col-2"> + <button nbButton ghost> + <nb-icon icon="trash-2-outline" status="danger" + (click)="deleteProperty(data.key, datasetMappedMetadatas)"> + </nb-icon> + </button> + </div> </div> - <div class="col-2"> - <button nbButton ghost> - <nb-icon icon="trash-2-outline" status="danger" - (click)="deleteProperty(data.key)"> - </nb-icon> - </button> + </nb-list-item> + + </nb-list> + </nb-card> + <nb-card> + <nb-card-header>Distribution</nb-card-header> + + <nb-list> + <nb-list-item + *ngFor="let data of distributionMappedMetadatas[index] | keyvalue; trackBy:trackByIndex; "> + <div class="row"> + <div class="col-3"><label + for="{{data.key}}">{{distributions[data.key].uri}}</label> + </div> + <div class="col-7"> + <ng-template #normal> + <input nbInput [ngModel]="data.value" + (ngModelChange)="distributionMappedMetadatas[index].set(data.key, $event)" /> + </ng-template> + <ng-container + *ngIf="isArray(data.value) && !isReplicable(distributions[data.key].card); else normal"> + <input nbInput [ngModel]="data.value[0]" + (ngModelChange)="distributionMappedMetadatas[index].set(data.key, $event)" /> + </ng-container> + <ng-container + *ngIf="isArray(data.value) && isReplicable(distributions[data.key].card)"> + <ul *ngFor="let val of data.value" style="margin-left: -100px;"> + <li> + <div class="row"> + <div class="col-3"> + <label + for="{{data.key}}">{{distributions[data.key].uri}}</label> + </div> + <div class="col-7"> + <input nbInput [ngModel]="val" + (ngModelChange)="distributionMappedMetadatas[index].set(data.key, $event)" /> + </div> + <div class="col-2"> + + </div> + </div> + </li> + </ul> + </ng-container> + + </div> + <div class="col-2"> + <button nbButton ghost> + <nb-icon icon="trash-2-outline" status="danger" + (click)="deleteProperty(data.key, distributionMappedMetadatas)"> + </nb-icon> + </button> + </div> </div> - </div> - </nb-list-item> + </nb-list-item> - </nb-list> + </nb-list> + </nb-card> <div class="row"> <button class="button-center" nbButton status="danger" *ngIf=" !first " - (click)="mappedMetadatas.splice(index, 1); prev()">Delete datset<nb-icon + (click)="distributionMappedMetadatas.splice(index, 1); prev()">Delete dataset<nb-icon icon="trash-2-outline"> </nb-icon></button> </div> @@ -175,7 +301,7 @@ <div *ngIf="!first "> <button nbButton (click)=" next()" - [disabled]="index == mappedMetadatas.length -1">next</button> + [disabled]="index == itemsdataset.length -1">next</button> </div> </div> @@ -216,7 +342,7 @@ </div> <div> - <button nbButton (click)=" next()" [disabled]="index == mappedMetadatas.length -1" + <button nbButton (click)=" next()" [disabled]="index == datasetMappedMetadatas.length -1" [disabled]="index == itemsdataset.length -1 ">next</button> </div> @@ -231,4 +357,4 @@ </nb-card-footer> </nb-card> -</ng-template> +</ng-template> \ No newline at end of file diff --git a/src/app/mapping/mapping.component.scss b/src/app/mapping/mapping.component.scss index 68382b72937c99e6d9009eed3e99282479d2745e..48e53e376751c9debd1eaca7700c778176dd3ea0 100644 --- a/src/app/mapping/mapping.component.scss +++ b/src/app/mapping/mapping.component.scss @@ -17,7 +17,7 @@ margin: 10px 10px; } - input:disabled{ + .inputDisabled{ color: black } diff --git a/src/app/mapping/mapping.component.ts b/src/app/mapping/mapping.component.ts index 7977cb529d7cc17982c15984c1fe737d63acee0e..8c96f2d4980586f229fe1775a043161851cb310b 100644 --- a/src/app/mapping/mapping.component.ts +++ b/src/app/mapping/mapping.component.ts @@ -1,19 +1,21 @@ import { HttpResponse } from '@angular/common/http'; -import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { AfterContentChecked, AfterViewChecked, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core'; import { FormArray } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { FileSaverService } from 'ngx-filesaver'; +import { version } from 'process'; import { Observable, of, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; import { environment } from 'src/environments/environment.prod'; import { DatasetCrudService } from '../datasets/services/dataset-crud.service'; -import { Dataset, DatasetPath } from './class/dataset'; +import { Property, DatasetPath, Distribution, ResponseFileTsv, OldProperty } from './class/dataset'; import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialog.component'; +import { MappingService } from './service/mapping.service'; @Component({ @@ -21,31 +23,40 @@ import { FeedbackDialogComponent } from './dialog/feedback-dialog/feedback-dialo templateUrl: './mapping.component.html', styleUrls: ['./mapping.component.scss'] }) -export class MappingComponent implements OnInit { +export class MappingComponent implements OnInit, OnDestroy { + datasetPathArray: DatasetPath[] = []; + addDistribution = false + check = false; + distributions: Property[] = []; ontology: string; urls: any[] = []; - itemsdataset: any[] = []; - dcatVocabulary: Dataset[]; - vocabularies: Dataset[]; + itemsdataset: any[] = [] + datasets: Property[]; + vocabularies: Property[]; filteredOptions: Observable<string[]>; keys: string[] = []; - selectedPaths: string[] ; - mappedMetadatas: Map<number, string>[] = []; - DatasetToPublish: Map<string, string>[]; + selectedPaths: string[]; + distributionSelectedPaths: string[]; + datasetMappedMetadatas: Map<number, string>[] = []; + distributionMappedMetadatas: Map<number, string>[] = []; index: number = 0 first: boolean = true; loading = false; loadingCr = false; FDP_URL = environment.fdpUrl; - Object: Object; ids: number[]; default = true; @ViewChild('autoInput') input; @Input() type: string; @Input() catalogId: any; - constructor(private dataSetService: DatasetCrudService, private dialog: MatDialog, private route: Router, private fileSaverService: FileSaverService) { } + constructor(private ref: ChangeDetectorRef,private dataSetService: DatasetCrudService, private dialog: MatDialog, private route: Router, private fileSaverService: FileSaverService, private mappingService: MappingService) { + ref.detach(); + setInterval(() => { + this.ref.detectChanges(); + }, 1000); + } ngOnInit() { console.log(this.type) @@ -54,7 +65,7 @@ export class MappingComponent implements OnInit { console.log(this.itemsdataset) this.ids = this.dataSetService.ids; this.keys = []; - this.type == "Dataverse" ? this.getKeysFromMetadataDataverse(this.itemsdataset[0], '') : this.getKeysFromMetadataCustom(this.itemsdataset[0], ''); + this.type == "Dataverse" ? this.getKeysFromMetadataCustom(this.itemsdataset[0], '') : this.getKeysFromMetadataCustom(this.itemsdataset[0], ''); this.keys = Array.from(new Set(this.keys)); this.filteredOptions = of(this.keys); } else { @@ -64,20 +75,30 @@ export class MappingComponent implements OnInit { } + + selectOntology(): void { - - this.dataSetService.getLocally('./assets/'+ this.ontology + '.json').subscribe( - dataset => { - this.dcatVocabulary = dataset; - this.vocabularies = dataset; - console.log(this.dcatVocabulary.length) + this.dataSetService.getLocally(`./assets/geodcat.json`).subscribe( + datasets => { + this.datasets = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets; + this.vocabularies = this.ontology === "dcat" ? datasets.filter(d => !d.geodcat) : datasets; + this.vocabularies.forEach(dataset => dataset.dcatClass = 'dcat:dataset'); this.selectedPaths = []; + this.dataSetService.getLocally('./assets/distribution.json').subscribe( + (distributions: Distribution[]) => { + this.distributions = this.ontology === "dcat" ? distributions.filter(d => !d.geodcat) : distributions; + this.distributions.forEach(distribution => distribution.dcatClass = 'dcat:distribution'); + this.vocabularies = this.vocabularies.concat(this.ontology === "dcat" ? this.distributions.filter(d => !d.geodcat) : distributions); + this.distributionSelectedPaths = []; + } + ); }, error => { console.error(error); }, ); -} + + } mapFromXslt() { @@ -100,73 +121,31 @@ export class MappingComponent implements OnInit { } - createDataset(item: Object): Map<number, string> { - console.log("rerereer" + this.selectedPaths) + createDataset(item: Object, classDcat: string): Map<number, string> { let mappedMetadata: Map<number, string> = new Map() - for (let i = 0; i < this.selectedPaths.length; i++) { - if (this.selectedPaths[i]) { - let tab = this.selectedPaths[i].split(' : '); - this.type == "Dataverse" ? mappedMetadata.set(i, this.getValueDataverse(tab, item)) : mappedMetadata.set(i, this.getValueCustom(tab, item)); + const array: string[] = (classDcat === "dataset") ? this.selectedPaths : this.distributionSelectedPaths + for (let i = 0; i < array.length; i++) { + if (array[i] && array.length > 0) { + let tab = array[i].split(' : '); + this.type == "Dataverse" ? mappedMetadata.set(i, this.getValueCustom(tab, item)) : mappedMetadata.set(i, this.getValueCustom(tab, item)); } } this.loadingCr = false; return mappedMetadata; } - publishDataset() { - let version = false; + publishDataset(): void { + let properties = "" let data: string = ''; - let properties: string = ''; let postedDatastes = []; let notPostedDatasets = []; this.loading = true; const requestPromises: Promise<any>[] = []; - for (let i = 0; i < this.mappedMetadatas.length; i++) { - properties = ""; - this.mappedMetadatas[i].forEach((value: string, index: number) => { - let key = this.dcatVocabulary[index].identifier; - if (key === 'dct:hasVersion') { - version = true; - } - - if (Array.isArray(value)) { - if (this.isMultiple(key)) { - value.forEach(v => { - properties += this.writeRdf(key, v); - }) - } else { - properties += this.writeRdf(key, value[0]); - } - } else { - properties += this.writeRdf(key, value); - } - - }) + for (let i = 0; i < this.datasetMappedMetadatas.length; i++) { - if (!version) properties += "dct:hasVersion \"undefined\";\n"; - data = '\@prefix dcat: <http://www.w3.org/ns/dcat#>.\n\ - @prefix dct: <http://purl.org/dc/terms/>.\n\ - @prefix adms: <http://www.w3.org/ns/adms#> .\n\ - @prefix dqv: <http://www.w3.org/ns/dqv#> .\n\ - @prefix geodcat: <http://data.europa.eu/930/>.\n\ - @prefix prov: <http://www.w3.org/ns/prov#>. \n\ - @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. \n\ - @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>.\n\ - @prefix s: <'+ this.FDP_URL + '/>.\n\ - @prefix c: <'+ this.FDP_URL + '/catalog/>.\n\ - \n\ - s:new\n\ - a dcat:Dataset, dcat:Resource;\n\ - dct:isPartOf c:'+ this.catalogId + ';\n' + properties + '.'; - - /*let query = 'query=PREFIX dcat: <http://www.w3.org/ns/dcat#>\n\ - PREFIX dct: <http://purl.org/dc/terms/>\n\ - SELECT ?dataset\n\ - where {\n\ - ?dataset a dcat:Dataset;\n\ - dct:title "' + title + '" ;\n\ - dct:isPartOf <https://f2ds.eosc-pillar.eu/catalog/' + this.catalogId + '>. } '*/ + properties = this.buildRDF(this.datasets, this.datasetMappedMetadatas, i); + data = this.getDatasetEmpty(properties); let requestPromise = this.dataSetService.createDataset(data).then((resp: HttpResponse<any>) => { if (resp.status.toString().startsWith('2')) { @@ -174,6 +153,15 @@ export class MappingComponent implements OnInit { } else { notPostedDatasets.push(this.ids[i]); } + + const location = resp.headers.get("location"); + const datasetId = location.substring(location.search("dataset/") + 8, location.length); + if (this.distributionMappedMetadatas.length > 0) { + const properties = this.buildRDF(this.distributions, this.distributionMappedMetadatas, i) + const distribution = this.getDistributionEmpty(properties, datasetId) + console.log(datasetId); + this.dataSetService.createDistribution(distribution).subscribe(); + } }) requestPromises.push(requestPromise); } @@ -189,6 +177,34 @@ export class MappingComponent implements OnInit { }) } + buildRDF(vocabularies: Property[], array: Map<number, string>[], i: number): string { + let properties = ""; + let version = false; + array[i].forEach((value: string, key: number) => { + let uri = vocabularies[key].uri; + if (uri === 'dct:hasVersion') { + version = true; + } + + if (Array.isArray(value)) { + if (this.isReplicable(this.getCard(uri))) { + value.forEach(v => { + properties += this.writeRdf(uri, v); + }) + } else { + properties += this.writeRdf(uri, value[0]); + } + } else { + properties += this.writeRdf(uri, value); + } + + }) + + if (!version) properties += `dct:hasVersion "undefined";\n`; + + return properties; + } + publishDatasetFromGeodcatApi() { let postedDatastes = []; let notPostedDatasets = []; @@ -222,48 +238,34 @@ export class MappingComponent implements OnInit { private writeRdf(key: string, value: string): string { let properties = ""; - (value && typeof value === "string") ? value = this.replaceAll(value, '\n', '') : value; + value = (value && typeof value === "string") ? value.replace(/\n/g, '') : value; switch (key) { case 'dcat:landingPage': - properties += key + ' <' + value + '>;\n'; - break; case 'dcat:theme': - properties += key + ' <' + value + '>;\n'; - break; case 'dcat:contactPoint': - properties += key + ' <' + value + '>;\n'; - break; + case 'dcat:accessURL': + case 'dcat:downloadURL': case 'dct:language': properties += key + ' <' + value + '>;\n'; break; case 'dct:issued': - properties += key + ' "' + value + '"^^xsd:dateTime;\n'; - break; case 'dct:modified': properties += key + ' "' + value + '"^^xsd:dateTime;\n'; break; default: - properties += key + ' "' + value + '";\n'; - break; + properties += key + ' "' + value + '";\n'; break; } return properties; } - private replaceAll(str: string, find: string, replace: string) { - if (str.includes(find)) { - const strT = str.replace(find, replace) - this.replaceAll(strT, find, replace) - } else { - return str; - } - } + /* function to get recursively all the keys and values from the JSON object */ getKeysFromMetadataCustom(obj: Object, keyParent: string) { Object.keys(obj).forEach(key => { if (typeof obj[key] === 'object') { - if (Array.isArray(obj[key])) { + if (Array.isArray(obj[key])) { obj[key].forEach(e => { if (typeof e === 'object') { Object.keys(e).forEach(k => { @@ -272,15 +274,15 @@ export class MappingComponent implements OnInit { this.getKeysFromMetadataCustom(e, keyParent + key + ' : '); } }); - this.keys.push(keyParent + key ) + this.keys.push(keyParent + key) this.getKeysFromMetadataCustom(obj[key], keyParent + key + ' : '); } else { - this.keys.push(keyParent + key ) + this.keys.push(keyParent + key) this.getKeysFromMetadataCustom(obj[key], keyParent + key + ' : '); } } else { - this.keys.push(keyParent + key ); + this.keys.push(keyParent + key); } }); @@ -335,7 +337,7 @@ export class MappingComponent implements OnInit { if (Array.isArray(obj) && obj.some(e => typeof e === 'object')) { let array = []; obj.forEach(e => { - if (e[tab[i]]){ + if (e[tab[i]]) { array.push(e[tab[i]]); } }); @@ -344,7 +346,7 @@ export class MappingComponent implements OnInit { let array = []; for (let element in obj) { obj[element].forEach(e => { - if (e[tab[i]]){ + if (e[tab[i]]) { array.push(e[tab[i]]); } }) @@ -413,11 +415,14 @@ export class MappingComponent implements OnInit { mapDataset() { this.loadingCr = true; - this.mappedMetadatas = []; + this.datasetMappedMetadatas = []; + this.distributionMappedMetadatas = []; this.itemsdataset.forEach((dataset: Object) => { - this.mappedMetadatas.push(this.createDataset(dataset)); + this.datasetMappedMetadatas.push(this.createDataset(dataset, "dataset")); + this.distributionMappedMetadatas.push(this.createDataset(dataset, "distribution")) }) - console.log(this.mappedMetadatas); + console.table(this.datasetMappedMetadatas); + console.log(this.distributionMappedMetadatas); this.first = false; } next() { @@ -438,87 +443,118 @@ export class MappingComponent implements OnInit { } downloadJson() { - let datasetPathArray: DatasetPath[] = []; - for (let i = 0; i < this.dcatVocabulary.length; i++) { + for (let i = 0; i < this.datasets.length; i++) { if (this.selectedPaths[i]) { - datasetPathArray.push(new DatasetPath(this.dcatVocabulary[i], this.selectedPaths[i])); - } else { - datasetPathArray.push(new DatasetPath(this.dcatVocabulary[i], "")); + this.datasetPathArray.push(new DatasetPath(this.datasets[i], this.selectedPaths[i], 'dcat:dataset')); } - } + for (let i = 0; i < this.distributions.length; i++) { + if (this.distributionSelectedPaths[i]) { + this.datasetPathArray.push(new DatasetPath(this.distributions[i], this.distributionSelectedPaths[i], 'dcat:distribution')) + } + } + console.table(this.datasetPathArray) - const fileName = 'paths.json'; + /*const fileName = 'paths.json'; const fileType = this.fileSaverService.genType(fileName); const txtBlob = new Blob([(JSON.stringify(datasetPathArray)).toString()], { type: fileName }); - this.fileSaverService.save(txtBlob, fileName); + this.fileSaverService.save(txtBlob, fileName);*/ + this.mappingService.downloadFile(this.datasetPathArray); } openFileInputDialog(): void { document.getElementById('file').click(); } + fillFromTsv(vocabulary: Property[], paths: string[], tsvFile: ResponseFileTsv[], dcatClass: string) { + for (let i = 0; i < tsvFile.length; i++) { + if (i > 0 && tsvFile[i].object_id === tsvFile[i - 1].object_id) { + const voc: Property = vocabulary.find(e => e.uri === tsvFile[i].object_id); + const index = vocabulary.indexOf(voc); + vocabulary.splice(index + 1, 0, voc); + paths.splice(index + 1, 0, tsvFile[i].subject_label); + } else { + const voc: Property = vocabulary.find(e => e.uri === tsvFile[i].object_id); + const index = vocabulary.indexOf(voc); + paths[index] = tsvFile[i].subject_label; + } + } + } + + importJson(event: Event) { const files: FileList = (event.target as HTMLInputElement).files; const jsonFile = files[0]; - console.log(jsonFile) - let reader = new FileReader(); - let datasetPath: DatasetPath[] = []; + const reader = new FileReader(); + reader.onloadend = () => { - datasetPath = <DatasetPath[]>JSON.parse(reader.result as string); - for (let i = 0; i < datasetPath.length; i++) { - this.selectedPaths[i] = datasetPath[i].path; - if (typeof datasetPath[i].dcatProperty !== 'object') { - this.dcatVocabulary[i] = this.vocabularies.filter(v => v.identifier === <string>datasetPath[i].dcatProperty)[0]; - } else { - this.dcatVocabulary[i] = <Dataset>datasetPath[i].dcatProperty; + if (jsonFile.name.split('.')[1] === "tsv") { + let paths: ResponseFileTsv[] = <ResponseFileTsv[]>this.mappingService.tsvToJson(reader.result as string); + let datasetPath: ResponseFileTsv[] = []; + let distributionPath: ResponseFileTsv[] = []; + console.table(paths) + paths.forEach(path => { + (path.object_category.includes('dataset')) ? datasetPath.push(path) : distributionPath.push(path); + }) + + console.log(datasetPath) + console.log(distributionPath) + if (distributionPath.length > 0) this.addDistribution = true; + this.fillFromTsv(this.datasets, this.selectedPaths, datasetPath, 'dcat:dataset'); + this.fillFromTsv(this.distributions, this.distributionSelectedPaths, distributionPath, 'dcat:distribution'); + } else { + let paths: DatasetPath[] = <DatasetPath[]> JSON.parse(reader.result as string); + console.table(paths) + + for (let i = 0; i < paths.length; i++) { + if (i > 0 && paths[i].dcatProperty === paths[i - 1].dcatProperty) { + const voc: Property = this.datasets.find(e => e.uri === (<Property>paths[i].dcatProperty).uri); + this.datasets.splice(i + 1, 0, voc); + this.selectedPaths.splice(i + 1, 0, paths[i].path); + + if (typeof paths[i].dcatProperty !== 'object') { + this.datasets[i] = this.vocabularies.filter(e => e.dcatClass === 'dcat:dataset').find(v => v.uri === <string>paths[i].dcatProperty); + } else { + this.datasets[i] = this.vocabularies.filter(e => e.dcatClass === 'dcat:dataset').find(v => v.uri === (<OldProperty><unknown>paths[i].dcatProperty).identifier); + } + + } else { + this.selectedPaths[i] = paths[i].path; + if (typeof paths[i].dcatProperty !== 'object') { + this.datasets[i] = this.vocabularies.find(v => v.uri === <string>paths[i].dcatProperty); + } else { + this.datasets[i] = this.vocabularies.find(v => v.uri === (<OldProperty><unknown>paths[i].dcatProperty).identifier); + } + } + + } } } reader.readAsText(jsonFile); + this.ref.markForCheck() + + } - addField(index: number) { - let addedDcat: Dataset = new Dataset(this.dcatVocabulary[index].name, this.dcatVocabulary[index].identifier, this.dcatVocabulary[index].usageNote, true); - this.dcatVocabulary.splice(index + 1, 0, addedDcat); - this.selectedPaths.splice(index + 1, 0, ''); - console.table(this.selectedPaths) - } - - deleteField(index: number) { - this.dcatVocabulary.splice(index, 1); - this.selectedPaths.splice(index, 1); - console.table(this.selectedPaths) + addField(index: number, properties: Property[], paths: string[]) { + let addedDcat: Property = properties.find(e => e.uri === properties[index].uri); + properties.splice(index + 1, 0, addedDcat); + + paths.splice(index + 1, 0, ''); + } - - isMultiple(vocabulary: string): boolean { - let bool: boolean = true; - switch (vocabulary) { - case "dct:isPartOf": - bool = false; - break; - case "dcat:landingPage": - bool = false; - break; - case "dcat:contactPoint": - bool = false; - break; - case "dct:title": - bool = false; - break; - default: - bool = true; - break; - } - return bool; + deleteField(index: number, properties: Property[], paths: string[]) { + properties.splice(index, 1); + paths.splice(index, 1); } // to delete a property of dcat dataset mapped - deleteProperty(key: number) { - this.mappedMetadatas[this.index].delete(key); + deleteProperty(key: number, map: Map<number, string>[]) { + map[this.index].delete(key); } - + trackByIndex(index: number): any { return index; } @@ -545,15 +581,66 @@ export class MappingComponent implements OnInit { toggle(checked: boolean) { this.default = checked; } -} - + toggleDistri(checked: boolean) { + this.addDistribution = checked; + } + isMandatory(card: string): boolean { + return card.startsWith("1"); + } + isReplicable(card: string): boolean { + return card.endsWith("n"); + } + getCard(uri: string): string { + return this.vocabularies.find((vocabulary: Property) => vocabulary.uri === uri).card; + } + ngOnDestroy(): void { + this.mappingService.postFile(this.datasetPathArray, this.catalogId).subscribe(); + } + private getDistributionEmpty(properties: string, datasetId: string): string { + return `@prefix dcat: <http://www.w3.org/ns/dcat#>. + @prefix dct: <http://purl.org/dc/terms/>. + @prefix adms: <http://www.w3.org/ns/adms#> . + @prefix dqv: <http://www.w3.org/ns/dqv#> . + @prefix geodcat: <http://data.europa.eu/930/>. + @prefix prov: <http://www.w3.org/ns/prov#>. + @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. + @prefix skos: <http://www.w3.org/2004/02/skos/core#>. + @prefix spdx: <http://spdx.org/rdf/terms#>. + @prefix foaf: <http://xmlns.com/foaf/0.1/>. + @prefix odrl: <http://www.w3.org/ns/odrl/2/>. + @prefix cnt: <http://www.w3.org/2011/content#>. + @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>. + @prefix s: <${this.FDP_URL}/>. + @prefix c: <${this.FDP_URL}/dataset/>. + + s:new + a dcat:Distribution, dcat:Resource; + dct:isPartOf c:${datasetId}; + ${properties}.`; + } -function addField(index: any, number: any) { - throw new Error('Function not implemented.'); + private getDatasetEmpty(properties: string): string { + return `@prefix dcat: <http://www.w3.org/ns/dcat#>. + @prefix dct: <http://purl.org/dc/terms/>. + @prefix adms: <http://www.w3.org/ns/adms#> . + @prefix dqv: <http://www.w3.org/ns/dqv#> . + @prefix geodcat: <http://data.europa.eu/930/>. + @prefix prov: <http://www.w3.org/ns/prov#>. + @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>. + @prefix language: <http://id.loc.gov/vocabulary/iso639-1/>. + @prefix s: <${this.FDP_URL}/>. + @prefix c: <${this.FDP_URL}/catalog/>. + + s:new + a dcat:Dataset, dcat:Resource; + dct:isPartOf c:${this.catalogId} ; + ${properties}.`; + } } + diff --git a/src/app/mapping/service/mapping.service.spec.ts b/src/app/mapping/service/mapping.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0023667071963b498f6238252fcace6623786e2b --- /dev/null +++ b/src/app/mapping/service/mapping.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { MappingService } from './mapping.service'; + +describe('MappingService', () => { + let service: MappingService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(MappingService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/mapping/service/mapping.service.ts b/src/app/mapping/service/mapping.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..b43b8d434d1f2fec9fa36b418fa31a83a2213405 --- /dev/null +++ b/src/app/mapping/service/mapping.service.ts @@ -0,0 +1,145 @@ +import { HttpClient, HttpHeaders, HttpRequest } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { TokenStorageService } from 'src/app/authentication/services/token-storage.service'; +import { SmartHarvesterUser } from 'src/app/user/model/user'; +import { environment } from 'src/environments/environment'; +import { DatasetPath } from '../class/dataset'; + +@Injectable({ + providedIn: 'root' +}) + +export class MappingService { + + fds2Token: string = this.storageService.getToken(); + + constructor(private storageService: TokenStorageService, private http: HttpClient) { } + + postFile(objArray: DatasetPath[], catalogId: String) { + + + + + + const body: Blob = new Blob(['\ufeff' + this.convertToTSV(objArray, [ + 'subject_label', + 'predicate_id', + 'object_id', + 'match_type', + 'object_category' + ])], { + type: 'text/tsv;charset=utf-8;', + }); + + const data: FormData = new FormData(); + data.append('file', body); + const req = new HttpRequest('POST', `${environment.smartharvesterUrl}/harvester/api/storeMapping/upload/${catalogId}`, data, { + headers: new HttpHeaders({ + + 'Authorization': 'Bearer ' + this.fds2Token + }), + reportProgress: true, + responseType: 'json' + }); + + return this.http.request(req); + + + } + + downloadFile(data: DatasetPath[], filename = 'dcatMapping') { + let tsvData = this.convertToTSV(data, [ + 'subject_label', + 'predicate_id', + 'object_id', + 'match_type', + 'object_category' + ]); + + let blob = new Blob(['\ufeff' + tsvData], { + type: 'text/tsv;charset=utf-8;', + }); + let dwldLink = document.createElement('a'); + let url = URL.createObjectURL(blob); + let safariBrowser = navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1; + if (safariBrowser) { + dwldLink.setAttribute('target', '_blank'); + } + dwldLink.setAttribute('href', url); + dwldLink.setAttribute('download', filename + '.tsv'); + dwldLink.style.visibility = 'hidden'; + document.body.appendChild(dwldLink); + dwldLink.click(); + document.body.removeChild(dwldLink); + } + + convertToTSV(objArray: DatasetPath[], headerList: string[]): string { + let date = new Date(); + let user: SmartHarvesterUser = this.storageService.getUser(); + let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray; + let str = `#mapping_date: ${date.getDate()}/${date.getMonth()}/${date.getFullYear()}\n#creator_label: ${user.firstName} ${user.lastName}\n#curie_map:\n# dcat: "http://www.w3.org/ns/dcat#"\n# dct: "http://purl.org/dc/terms/"\n# adms: "http://www.w3.org/ns/adms#\n# dqv: "http://www.w3.org/ns/dqv#"\n# geodcat: "http://data.europa.eu/930/"\n# prov: "http://www.w3.org/ns/prov#"\n# rdfs: "http://www.w3.org/2000/01/rdf-schema#"`; + let row = ''; + + for (let index in headerList) { + row += headerList[index] + '\t'; + } + row = row.slice(0, -1); + str += row + '\n'; + for (let i = 0; i < array.length; i++) { + + if (array[i].path) { + let line = ''; + for (let index in headerList) { + let head = headerList[index]; + switch (head) { + case 'subject_label': + line += array[i].path + '\t'; + break; + case 'predicate_id': + line += 'skos:exactMatch' + '\t'; + break; + case 'object_id': + line += array[i].dcatProperty.uri + '\t'; + break; + case 'match_type': + line += 'lexical' + '\t'; + break; + case 'object_category': + line += array[i].dcatClass + '\t'; + } + } + str += (i != array.length - 1) ? line + '\n' : line; + } + + + + } + return str; + } + + tsvToJson(tsv: string): Object { + let lines: string[] = tsv.split('\n'); + let result = []; + console.table(lines) + while (lines[0].startsWith('#')) { + lines.shift(); + } + + console.table(lines) + let headers = lines[0].split('\t'); + lines.shift() + for (let i = 0; i < lines.length; i++) { + + let obj = {}; + let currentLine = lines[i].split('\t'); + + for (var j = 0; j < headers.length; j++) { + obj[headers[j]] = currentLine[j]; + } + + result.push(obj); + } + + return result; + } +} diff --git a/src/app/publishapi/publishapi.component.ts b/src/app/publishapi/publishapi.component.ts index b525b3459d20db0ca2547381a67db4946836384b..a015db018d88a7594af09437e861192492f24d34 100644 --- a/src/app/publishapi/publishapi.component.ts +++ b/src/app/publishapi/publishapi.component.ts @@ -122,7 +122,6 @@ export class PublishApiComponent implements OnInit { this.openApi.info['x-catalog-id'] = catId; this.catalogSelect.selected = catId; this.onChangeRepository(catId); - this.type = this.getType(catId); } getTitleFromFdpApi(fdpApiResponse: FdpApiResponseItem[]): string { @@ -237,9 +236,10 @@ export class PublishApiComponent implements OnInit { } downloadJson(): void { + let windowVar: any = window.navigator; const newBlob = new Blob([this.openApiService.getPrettyJson(this.openApi)], { type: 'application/json' }); - if (window.navigator && window.navigator.msSaveOrOpenBlob) { - window.navigator.msSaveOrOpenBlob(newBlob); + if (windowVar && windowVar.msSaveOrOpenBlob) { + windowVar.msSaveOrOpenBlob(newBlob); return; } const data = window.URL.createObjectURL(newBlob); @@ -330,7 +330,6 @@ export class PublishApiComponent implements OnInit { this.openApi = this.openApiService.getFromString(reader.result as string); this.openApi.cleanServers(servers[0].url); this.openApi.info['x-catalog-id'] = catId; - this.type = this.getType(catId) }; reader.readAsText(jsonFile); diff --git a/src/app/repository/services/publish-repository.service.ts b/src/app/repository/services/publish-repository.service.ts index 5677cf78b83767e22b58185e02154c79fee9f9ba..f562c25dadc0b18e3cadc37d6b931c94749689fa 100644 --- a/src/app/repository/services/publish-repository.service.ts +++ b/src/app/repository/services/publish-repository.service.ts @@ -41,9 +41,9 @@ export class PublishRepositoryService { const myRequest = new Request(FDP_URL + "/catalog", myInit); const response = await fetch(myRequest, myInit); - const responseText = await response.text(); - - const catId = responseText.substring(38, 74); + const id = await response.headers.get("location"); + + const catId = id.substring(id.search("catalog/") + 8, id.length); console.log('catalog creaetd with fdp / id = ' + catId); return this.addUserCatalog(catId); } diff --git a/src/assets/distribution.json b/src/assets/distribution.json new file mode 100644 index 0000000000000000000000000000000000000000..eef15addccbc611dc9dfa058ef0323f44d131968 --- /dev/null +++ b/src/assets/distribution.json @@ -0,0 +1,229 @@ +[ + { + "property": "media type", + "uri": "dcat:mediaType", + "range": "dct:MediaType", + "usageNote": "This property refers to the media type of the Distribution as defined in the official register of media types managed by IANA.", + "card": "1..1", + "geodcat": false + }, + { + "property": "access URL", + "uri": "dcat:accessURL", + "range": "rdfs:Resource", + "usageNote": "This property contains a URL that gives access to a Distribution of the Dataset. The resource at the access URL may contain information about how to get the Dataset.", + "card": "1..n", + "geodcat": false + }, + { + "property": "Title", + "uri": "dct:title", + "range": "rdfs:Literal", + "usageNote": "This property contains a name given to the Distribution. This property can be repeated for parallel language versions of the description.", + "card": "1..n", + "geodcat": false + }, + { + "property": "compression format", + "uri": "dcat:compressFormat", + "range": "dct:MediaType", + "usageNote": "This property refers to the format of the file in which the data is contained in a compressed form, e.g. to reduce the size of the downloadable file. It SHOULD be expressed using a media type as defined in the official register of media types managed by IANA.", + "card": "0..1", + "geodcat": false + }, + { + "property": "availability", + "uri": "dcatap:availability", + "range": "skos:Concept", + "usageNote": "This property indicates how long it is planned to keep the Distribution of the Dataset available.", + "card": "0..1", + "geodcat": false + }, + { + "property": "description", + "uri": "dct:description", + "range": "rdfs:Literal", + "usageNote": "This property contains a free-text account of the Distribution. This property can be repeated for parallel language versions of the description.", + "card": "0..n", + "geodcat": false + }, + { + "property": "format", + "uri": "dct:format", + "range": "dct:MediaTypeOrExtent", + "usageNote": "This property refers to the file format of the Distribution.", + "card": "0..1", + "geodcat": false + }, + { + "property": "licence", + "uri": "dct:license", + "range": "dct:LicenseDocument", + "usageNote": "This property refers to the licence under which the Distribution is made available.", + "card": "0..1", + "geodcat": false + }, + { + "property": "access service", + "uri": "dcat:accessService", + "range": "dcat:DataService", + "usageNote": "This property refers to a data service that gives access to the distribution of the dataset", + "card": "0..n", + "geodcat": false + }, + { + "property": "byte size", + "uri": "dcat:byteSize", + "range": "rdfs:Literal typed as xsd:decimal", + "usageNote": "This property contains the size of a Distribution in bytes.", + "card": "0..1", + "geodcat": false + }, + { + "property": "Checksum", + "uri": "spdx:checksum", + "range": "spdx:Checksum", + "usageNote": "This property provides a mechanism that can be used to verify that the contents of a distribution have not changed. The checksum is related to the downloadURL.", + "card": "0..1", + "geodcat": false + }, + { + "property": "Documentation", + "uri": "foaf:page", + "range": "foaf:Document", + "usageNote": "This property refers to a page or document about this Distribution.", + "card": "0..n", + "geodcat": false + }, + { + "property": "download URL", + "uri": "dcat:downloadURL", + "range": "rdfs:Resource", + "usageNote": "This property contains a URL that is a direct link to a downloadable file in a given format.", + "card": "0..1", + "geodcat": false + }, + { + "property": "has policy", + "uri": "odrl:hasPolicy", + "range": "odrl:Policy", + "usageNote": "This property refers to the policy expressing the rights associated with the distribution if using the ODRL vocabulary", + "card": "0..1", + "geodcat": false + }, + { + "property": "Language", + "uri": "dct:language", + "range": "dct:LinguisticSystem", + "usageNote": "This property refers to a language used in the Distribution. This property can be repeated if the metadata is provided in multiple languages.", + "card": "0..n", + "geodcat": false + }, + { + "property": "linked schemas", + "uri": "dct:conformsTo", + "range": "dct:Standard", + "usageNote": "This property refers to an established schema to which the described Distribution conforms.", + "card": "0..n", + "geodcat": false + }, + { + "property": "packaging format", + "uri": "dcat:packageFormat", + "range": "dct:MediaType", + "usageNote": "This property refers to the format of the file in which one or more data files are grouped together, e.g. to enable a set of related files to be downloaded together. It SHOULD be expressed using a media type as defined in the official register of media types managed by IANA.", + "card": "0..1", + "geodcat": false + }, + { + "property": "release date", + "uri": "dct:issued", + "range": "rdfs:Literal typed as xsd:date or xsd:dateTime", + "usageNote": "This property contains the date of formal issuance (e.g., publication) of the Distribution.", + "card": "0..1", + "geodcat": false + }, + { + "property": "Rights", + "uri": "dct:rights", + "range": "dct:RightsStatement", + "usageNote": "This property refers to a statement that specifies rights associated with the Distribution.", + "card": "0..1", + "geodcat": false + }, + { + "property": "spatial resolution", + "uri": "dcat:spatialResolutionInMeters", + "range": "xsd:decimal", + "usageNote": "This property refers to the minimum spatial separation resolvable in a dataset distribution, measured in meters.", + "card": "0..n", + "geodcat": false + }, + { + "property": "status", + "uri": "adms:status", + "range": "skos:Concept", + "usageNote": "This property refers to the maturity of the Distribution. It MUST take one of the values Completed, Deprecated, Under Development, Withdrawn.", + "card": "0..1", + "geodcat": false + }, + { + "property": "temporal resolution", + "uri": "dcat:temporalResolution", + "range": "xsd:duration", + "usageNote": "This property refers to the minimum time period resolvable in the dataset distribution.", + "card": "0..n", + "geodcat": false + }, + { + "property": "update/ modification date", + "uri": "dct:modified", + "range": "rdfs:Literal typed as xsd:date or xsd:dateTime", + "usageNote": "This property contains the most recent date on which the Distribution was changed or modified.", + "card": "0..1", + "geodcat": false + }, + { + "property": "representation technique", + "uri": "adms:representationTechnique", + "range": "skos:Concept", + "usageNote": "This property MAY be used to provide more information about the format in which an Distribution is released. This is different from the file format as, for example, a ZIP file (file format) could contain an XML schema (representation technique). In GeoDCAT-AP, this property SHOULD be used to express the spatial representation type (grid, vector, tin), by using the URIs of the corresponding code list operated by the INSPIRE Registry [INSPIRE-SRT].", + "card": "0..1", + "geodcat": true + }, { + "property": "character encoding", + "uri": "cnt:characterEncoding", + "range": "rdfs:Literal", + "usageNote": "This property SHOULD be used to specify the character encoding of the Distribution, by using as value the character set names in the IANA register [IANA-CHARSETS].", + "card": "0..n", + "geodcat": true + }, { + "property": "access rights", + "uri": "dct:accessRights", + "range": "dct:RightsStatement", + "usageNote": "This property MAY include information regarding access or restrictions based on privacy, security, or other policies. For INSPIRE metadata, this property SHOULD be used with the URIs of the \"Limitations on public access \" code list operated by the INSPIRE Registry [INSPIRE-LPA].", + "card": "0..1", + "geodcat": true + }, { + "property": "reference system", + "uri": "dct:conformsTo", + "range": "dct:Standard", + "usageNote": "This property SHOULD be used to specify the reference system used in the Distribution. Spatial reference systems SHOULD be specified by using the corresponding URIs from the “EPSG coordinate reference systems†register operated by OGC [OGC-EPSG].", + "card": "0..n", + "geodcat": true + }, { + "property": "spatial resolution", + "uri": "dqv:hasQualityMeasurement", + "range": "dqv:QualityMeasurement", + "usageNote": "Refers to the performed quality measurements. In GeoDCAT-AP, this property is used to specify \"spatial resolution\", as defined in [INSPIRE-MD-REG], [ISO-19115], and [ISO-19115-1].", + "card": "0..n", + "geodcat": true + }, { + "property": "spatial resolution as text", + "uri": "rdfs:comment", + "range": "rdfs:Literal", + "usageNote": "This property MAY be used to express spatial resolution types that cannot be specified via dcat:spatialResolutionInMeters - i.e., spatial resolution as equivalent scale, angular distance, vertical distance.", + "card": "0..n", + "geodcat": true + } +] \ No newline at end of file diff --git a/src/assets/geodcat.json b/src/assets/geodcat.json index 2e03a40894b47ed928540e058efd009940c01330..5f235ddbaf0aaf9a23ea748676f6e0712401865a 100644 --- a/src/assets/geodcat.json +++ b/src/assets/geodcat.json @@ -1,242 +1,338 @@ [ { - "name": "title", - "identifier": "dct:title", - "usageNote": "Mandatory property. This property contains a name given to the Dataset. This property can be repeated for parallel language versions of the name." + "property": "title", + "uri": "dct:title", + "usageNote": "Mandatory property. This property contains a property given to the Dataset. This property can be repeated for parallel language versions of the name.", + "card": "1..1", + "geodcat": false }, { - "name": "has Version", - "identifier": "dct:hasVersion", - "usageNote": "Optional property.This property refers to a related Dataset that is a version, edition, or adaptation of the described Dataset." + "property": "has Version", + "uri": "dct:hasVersion", + "usageNote": "Optional property.This property refers to a related Dataset that is a version, edition, or adaptation of the described Dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "description", - "identifier": "dct:description", - "usageNote": "Mandatory property. This property contains a free-text account of the Dataset. This property can be repeated for parallel language versions of the description." + "property": "description", + "uri": "dct:description", + "usageNote": "Mandatory property. This property contains a free-text account of the Dataset. This property can be repeated for parallel language versions of the description.", + "card": "1..n", + "geodcat": false }, { - "name": "contact point", - "identifier": "dcat:contactPoint", - "usageNote": "Recommended property.This property contains contact information that can be used for sending comments about the Dataset." + "property": "contact point", + "uri": "dcat:contactPoint", + "usageNote": "Recommended property.This property contains contact information that can be used for sending comments about the Dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "dataset distribution", - "identifier": "dcat:distribution", - "usageNote": "Recommended property. This property links the Dataset to an available Distribution." + "property": "dataset distribution", + "uri": "dcat:distribution", + "usageNote": "Recommended property. This property links the Dataset to an available Distribution.", + "card": "0..n", + "geodcat": false }, { - "name": "keyword/ tag", - "identifier": "dcat:keyword", - "usageNote": "Recommended property. This property contains a keyword or tag describing the Dataset." + "property": "keyword/ tag", + "uri": "dcat:keyword", + "usageNote": "Recommended property. This property contains a keyword or tag describing the Dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "publisher", - "identifier": "dct:publisher", - "usageNote": "Recommended property. This property refers to an entity (organisation) responsible for making the Dataset available." + "property": "publisher", + "uri": "dct:publisher", + "usageNote": "Recommended property. This property refers to an entity (organisation) responsible for making the Dataset available.", + "card": "0..1", + "geodcat": false }, { - "name": "spatial/geographical coverage", - "identifier": "dct:spatial", - "usageNote": "Recommended property. This property refers to a geographic region that is covered by the Dataset. " + "property": "spatial/geographical coverage", + "uri": "dct:spatial", + "usageNote": "Recommended property. This property refers to a geographic region that is covered by the Dataset. ", + "card": "0..n", + "geodcat": false }, { - "name": "theme/category", - "identifier": "dcat:theme", - "usageNote": "Recommended property. This property refers to a category of the Dataset. A Dataset may be associated with multiple themes. Subproperty of dct:subject." + "property": "theme/category", + "uri": "dcat:theme", + "usageNote": "Recommended property. This property refers to a category of the Dataset. A Dataset may be associated with multiple themes. Subproperty of dct:subject.", + "card": "0..n", + "geodcat": false }, { - "name": "temporal coverage", - "identifier": "dct:temporal", - "usageNote": "Recommended property. This property refers to a temporal period that the Dataset covers." + "property": "temporal coverage", + "uri": "dct:temporal", + "usageNote": "Recommended property. This property refers to a temporal period that the Dataset covers.", + "card": "0..n", + "geodcat": false }, { - "name": "conforms to", - "identifier": "dct:conformsTo", - "usageNote": "Optional property. This property refers to an implementing rule or other specification." + "property": "conforms to", + "uri": "dct:conformsTo", + "usageNote": "Optional property. This property refers to an implementing rule or other specification.", + "card": "0..n", + "geodcat": false }, { - "name": "creation date", - "identifier": "dct:created", - "usageNote": "This property contains the date on which the Dataset has been first created." + "property": "creation date", + "uri": "dct:created", + "usageNote": "Optional property. This property contains the date on which the Dataset has been first created.", + "card": "0..1", + "geodcat": true }, { - "name": "frequency", - "identifier": "dct:accrualPeriodicity", - "usageNote": "Optional property. This property refers to the frequency at which Dataset is updated." + "property": "frequency", + "uri": "dct:accrualPeriodicity", + "usageNote": "Optional property. This property refers to the frequency at which Dataset is updated.", + "card": "0..1", + "geodcat": false }, { - "name": "identifier", - "identifier": "dct:identifier", - "usageNote": "Optional property. This property contains the main identifier for the Dataset, e.g. the URI or other unique identifier in the context of the Catalogue." + "property": "identifier", + "uri": "dct:identifier", + "usageNote": "Optional property. This property contains the main identifier for the Dataset, e.g. the URI or other unique identifier in the context of the Catalogue.", + "card": "0..n", + "geodcat": false }, { - "name": "landing page", - "identifier": "dcat:landingPage", - "usageNote": "Optional property. This property refers to a web page that provides access to the Dataset, its Distributions and/or additional information." + "property": "landing page", + "uri": "dcat:landingPage", + "usageNote": "Optional property. This property refers to a web page that provides access to the Dataset, its Distributions and/or additional information.", + "card": "0..n", + "geodcat": false }, { - "name": "language", - "identifier": "dct:language", - "usageNote": "Optional property. This property refers to a language of the Dataset. This property can be repeated if there are multiple languages in the Dataset." + "property": "language", + "uri": "dct:language", + "usageNote": "Optional property. This property refers to a language of the Dataset. This property can be repeated if there are multiple languages in the Dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "other identifier", - "identifier": "adms:identifier", - "usageNote": "Optional property. This property refers to a secondary identifier of the Dataset, such as MAST/ADS[1], DataCite[2], DOI[3], EZID[4] or W3ID[5]." + "property": "other identifier", + "uri": "adms:identifier", + "usageNote": "Optional property. This property refers to a secondary identifier of the Dataset, such as MAST/ADS[1], DataCite[2], DOI[3], EZID[4] or W3ID[5].", + "card": "0..n", + "geodcat": false }, { - "name": "release date ", - "identifier": "dct:issued", - "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset." + "property": "release date ", + "uri": "dct:issued", + "usageNote": "Optional property. This property contains the date of formal issuance (e.g., publication) of the Dataset.", + "card": "0..1", + "geodcat": false }, { - "name": "rights holder", - "identifier": "dct:rightsHolder", - "usageNote": "This property refers to an Agent (organisation) holding rights on the Dataset." + "property": "rights holder", + "uri": "dct:rightsHolder", + "usageNote": "Optional property. This property refers to an Agent (organisation) holding rights on the Dataset.", + "card": "0..n", + "geodcat": true }, { - "name": "update/modification date", - "identifier": "dct:modified", - "usageNote": "Optional property. This property contains the most recent date on which the Dataset was changed or modified." + "property": "update/modification date", + "uri": "dct:modified", + "usageNote": "Optional property. This property contains the most recent date on which the Dataset was changed or modified.", + "card": "0..1", + "geodcat": false }, { - "name": "provenance", - "identifier": "dct:provenance", - "usageNote": "Optional property. This property contains a statement about the lineage of a Dataset." + "property": "provenance", + "uri": "dct:provenance", + "usageNote": "Optional property. This property contains a statement about the lineage of a Dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "sample", - "identifier": "adms:sample", - "usageNote": "Optional property. This property refers to a sample distribution of the dataset." + "property": "sample", + "uri": "adms:sample", + "usageNote": "Optional property. This property refers to a sample distribution of the dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "source", - "identifier": "dct:source", - "usageNote": "Optional property. This property refers to a related Dataset from which the described Dataset is derived." + "property": "source", + "uri": "dct:source", + "usageNote": "Optional property. This property refers to a related Dataset from which the described Dataset is derived.", + "card": "0..n", + "geodcat": false }, { - "name": "topic category", - "identifier": "dct:subject", - "usageNote": "In GeoDCAT-AP, this property SHOULD take as value one of the URIs of the \"Topic categories in accordance with EN ISO 19115\" code list operated by the INSPIRE Registry [INSPIRE-TC]." + "property": "topic category", + "uri": "dct:subject", + "usageNote": "Optional property. In GeoDCAT-AP, this property SHOULD take as value one of the URIs of the \"Topic categories in accordance with EN ISO 19115\" code list operated by the INSPIRE Registry [INSPIRE-TC].", + "card": "0..n", + "geodcat": true }, { - "name": "type", - "identifier": "dct:type", - "usageNote": "Optional property. This property refers to the type of the Dataset. A controlled vocabulary for the values has not been established." + "property": "type", + "uri": "dct:type", + "usageNote": "Optional property. This property refers to the type of the Dataset. A controlled vocabulary for the values has not been established.", + "card": "0..1", + "geodcat": false }, { - "name": "related resource", - "identifier": "dct:relation", - "usageNote": "Optional property. This property refers to a related resource." + "property": "related resource", + "uri": "dct:relation", + "usageNote": "Optional property. This property refers to a related resource.", + "card": "0..n", + "geodcat": false }, { - "name": "version", - "identifier": "owl:versionInfo", - "usageNote": "Optional property. This property contains a version number or other version designation of the Dataset." + "property": "version", + "uri": "owl:versionInfo", + "usageNote": "Optional property. This property contains a version number or other version designation of the Dataset.", + "card": "0..1", + "geodcat": false }, { - "name": "version notes", - "identifier": "adms:versionNotes", - "usageNote": "Optional property. This property contains a description of the differences between this version and a previous version of the Dataset." + "property": "version notes", + "uri": "adms:versionNotes", + "usageNote": "Optional property. This property contains a description of the differences between this version and a previous version of the Dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "is Version Of", - "identifier": "dct:isVersionOf", - "usageNote": "Optional property. This property refers to a related Dataset of which the described Dataset is a version, edition, or adaptation." + "property": "is Version Of", + "uri": "dct:isVersionOf", + "usageNote": "Optional property. This property refers to a related Dataset of which the described Dataset is a version, edition, or adaptation.", + "card": "0..n", + "geodcat": false }, { - "name": "documentation", - "identifier": "foaf:page", - "usageNote": "Optional property. This property refers to a page or document about this Dataset." + "property": "documentation", + "uri": "foaf:page", + "usageNote": "Optional property. This property refers to a page or document about this Dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "access rights", - "identifier": "dct:accessRights", - "usageNote": "Optional property. This property refers to information that indicates whether the Dataset is open data, has access restrictions or is not public. A controlled vocabulary with three members (:public, :restricted, :non-public) will be created and maintained by the Publications Office of the EU." + "property": "access rights", + "uri": "dct:accessRights", + "usageNote": "Optional property. This property refers to information that indicates whether the Dataset is open data, has access restrictions or is not public. A controlled vocabulary with three members (:public, :restricted, :non-public) will be created and maintained by the Publications Office of the EU.", + "card": "0..1", + "geodcat": false }, { - "name": "creator", - "identifier": "dct:creator", - "usageNote": "Optional property. This property refers to an entity primarily responsible for making the resource." + "property": "creator", + "uri": "dct:creator", + "usageNote": "Optional property. This property refers to an entity primarily responsible for making the resource.", + "card": "0..1", + "geodcat": false }, { - "name": "qualified attribution", - "identifier": "prov:qualifiedAttribution", - "usageNote": "Optional property. This property refers to the link to an Agent having some form of responsibility for the resource. " + "property": "qualified attribution", + "uri": "prov:qualifiedAttribution", + "usageNote": "Optional property. This property refers to the link to an Agent having some form of responsibility for the resource. ", + "card": "0..n", + "geodcat": false }, { - "name": "was generated by", - "identifier": "prov:wasGeneratedBy", - "usageNote": "Optional property. This property refers to an activity that generated, or provides the business context for, the creation of the dataset." + "property": "was generated by", + "uri": "prov:wasGeneratedBy", + "usageNote": "Optional property. This property refers to an activity that generated, or provides the business context for, the creation of the dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "was used by", - "identifier": "prov:wasUsedBy", - "usageNote": "This property refers to an Activity that used the Dataset. In GeoDCAT-AP, this property MAY be used to specify a testing Activity over a Dataset, against a given Standard, producing as output a conformance degree." + "property": "was used by", + "uri": "prov:wasUsedBy", + "usageNote": "Optional property. This property refers to an Activity that used the Dataset. In GeoDCAT-AP, this property MAY be used to specify a testing Activity over a Dataset, against a given Standard, producing as output a conformance degree.", + "card": "0..n", + "geodcat": true }, { - "name": "temporal resolution", - "identifier": "dcat:temporalResolution", - "usageNote": "This property refers to the minimum time period resolvable in the dataset." + "property": "temporal resolution", + "uri": "dcat:temporalResolution", + "usageNote": "This property refers to the minimum time period resolvable in the dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "spatial resolution", - "identifier": "dqv:hasQualityMeasurement", - "usageNote": "Refers to the performed quality measurements. In GeoDCAT-AP, this property is used to specify \"spatial resolution\", as defined in [INSPIRE-MD-REG], [ISO-19115], and [ISO-19115-1]." + "property": "spatial resolution", + "uri": "dqv:hasQualityMeasurement", + "usageNote": "Optional property. Refers to the performed quality measurements. In GeoDCAT-AP, this property is used to specify \"spatial resolution\", as defined in [INSPIRE-MD-REG], [ISO-19115], and [ISO-19115-1].", + "card": "0..n", + "geodcat": true }, { - "name": "spatial resolution in metres", - "identifier": "dcat:spatialResolutionInMeters", - "usageNote": "Optional property. This property refers to the minimum spatial separation resolvable in a dataset, measured in meters. " + "property": "spatial resolution in metres", + "uri": "dcat:spatialResolutionInMeters", + "usageNote": "Optional property. This property refers to the minimum spatial separation resolvable in a dataset, measured in meters. ", + "card": "0..n", + "geodcat": false }, { - "name": "spatial resolution as text", - "identifier": "rdfs:comment", - "usageNote": "This property MAY be used to express spatial resolution as free-text, when it cannot be specified via dqv:hasQualityMeasurement and dcat:spatialResolutionInMeters." + "property": "spatial resolution as text", + "uri": "rdfs:comment", + "usageNote": "Optional property. This property MAY be used to express spatial resolution as free-text, when it cannot be specified via dqv:hasQualityMeasurement and dcat:spatialResolutionInMeters. ", + "card": "0..n", + "geodcat": true }, { - "name": "qualified Relation", - "identifier": "dcat:qualifiedRelation", - "usageNote": "Optional property. This property provides a link to a description of a relationship with another resource." + "property": "is reference by", + "uri": "dct:isReferencedBy", + "usageNote": "Optional property. This property refers to a related resource, such as a publication, that references, cites, or otherwise points to the dataset.", + "card": "0..n", + "geodcat": false }, { - "name": "is reference by", - "identifier": "dct:isReferencedBy", - "usageNote": "Optional property. This property refers to a related resource, such as a publication, that references, cites, or otherwise points to the dataset." + "property": "custodian", + "uri": "geodcat:custodian", + "usageNote": "Optional property. Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource [ISO-19115].", + "card": "0..n", + "geodcat": true }, { - "name": "custodian", - "identifier": "geodcat:custodian", - "usageNote": "Party that accepts accountability and responsibility for the data and ensures appropriate care and maintenance of the resource [ISO-19115]." + "property": "distributor", + "uri": "geodcat:distributor", + "usageNote": "Optional property. Party who distributes the resource [ISO-19115].", + "card": "0..n", + "geodcat": true }, { - "name": "distributor", - "identifier": "geodcat:distributor", - "usageNote": "Party who distributes the resource [ISO-19115]." + "property": "originator", + "uri": "geodcat:originator", + "usageNote": "Optional property. Party who created the resource [ISO-19115].", + "card": "0..n", + "geodcat": true }, { - "name": "originator", - "identifier": "geodcat:originator", - "usageNote": "Party who created the resource [ISO-19115]." + "property": "principal investigator", + "uri": "geodcat:principalInvestigator", + "usageNote": "Optional property. Key party responsible for gathering information and conducting research [ISO-19115].", + "card": "0..n", + "geodcat": true }, { - "name": "principal investigator", - "identifier": "geodcat:principalInvestigator", - "usageNote": "Key party responsible for gathering information and conducting research [ISO-19115]." + "property": "processor", + "uri": "geodcat:processor", + "usageNote": "Optional property. Party who has processed the data in a manner such that the resource has been modified [ISO-19115].", + "card": "0..n", + "geodcat": true }, { - "name": "processor", - "identifier": "geodcat:processor", - "usageNote": "Party who has processed the data in a manner such that the resource has been modified [ISO-19115]." + "property": "resource provider", + "uri": "geodcat:resourceProvider", + "usageNote": "Optional property. Party that supplies the resource [ISO-19115].", + "card": "0..n", + "geodcat": true }, { - "name": "resource provider", - "identifier": "geodcat:resourceProvider", - "usageNote": "Party that supplies the resource [ISO-19115]." + "property": "user", + "uri": "geodcat:user", + "usageNote": "Optional property. Party who uses the resource [ISO-19115].", + "card": "0..n", + "geodcat": true }, { - "name": "user", - "identifier": "geodcat:user", - "usageNote": "Party who uses the resource [ISO-19115]." + "property": "qualified Relation", + "uri": "dcat:qualifiedRelation", + "usageNote": "Optional property. This property provides a link to a description of a relationship with another resource.", + "card": "0..n", + "geodcat": false } ] \ No newline at end of file diff --git a/version b/version index 51066d2ddd04cdf3b65c41ebc7250edeb274bdd1..0828ab79473bf97cc6631bc41685fc0242a17e44 100644 --- a/version +++ b/version @@ -1 +1 @@ -v17 \ No newline at end of file +v18 \ No newline at end of file