geonetwork-ui 2.3.0-dev.376e0e90 → 2.3.0-dev.f736344f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/esm2022/libs/api/metadata-converter/src/index.mjs +5 -5
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/atomic-operations.mjs +3 -3
  3. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +3 -3
  4. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.mjs +52 -0
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.mjs +14 -0
  6. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.mjs +48 -0
  7. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.mjs +18 -0
  8. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.mjs +64 -0
  9. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/converter.mjs +130 -0
  10. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +62 -58
  11. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +58 -75
  12. package/esm2022/libs/api/metadata-converter/src/lib/metadata-base.mapper.mjs +14 -0
  13. package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +14 -76
  14. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +4 -4
  15. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  16. package/esm2022/libs/feature/editor/src/lib/services/editor.service.mjs +8 -8
  17. package/fesm2022/geonetwork-ui.mjs +245 -822
  18. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  19. package/libs/api/metadata-converter/src/index.d.ts +4 -4
  20. package/libs/api/metadata-converter/src/index.d.ts.map +1 -1
  21. package/libs/api/metadata-converter/src/lib/gn4/{gn4.converter.d.ts → gn4.metadata.mapper.d.ts} +5 -5
  22. package/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.d.ts.map +1 -0
  23. package/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.d.ts.map +1 -0
  24. package/libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.d.ts.map +1 -0
  25. package/libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.d.ts.map +1 -0
  26. package/libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.d.ts.map +1 -0
  27. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts +4 -0
  28. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts.map +1 -0
  29. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +6 -34
  30. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  31. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +3 -39
  32. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  33. package/libs/api/metadata-converter/src/lib/{base.converter.d.ts → metadata-base.mapper.d.ts} +3 -3
  34. package/libs/api/metadata-converter/src/lib/metadata-base.mapper.d.ts.map +1 -0
  35. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts +1 -14
  36. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts.map +1 -1
  37. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +2 -2
  38. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  39. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +4 -6
  40. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  41. package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/src/libs/api/metadata-converter/src/index.ts +4 -4
  44. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +5 -32
  45. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +4 -11
  46. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +7 -33
  47. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +2 -2
  48. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +2 -2
  49. package/src/libs/api/metadata-converter/src/lib/gn4/{gn4.converter.ts → gn4.metadata.mapper.ts} +2 -2
  50. package/src/libs/api/metadata-converter/src/lib/iso19139/converter.ts +196 -0
  51. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +82 -121
  52. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +95 -175
  53. package/src/libs/api/metadata-converter/src/lib/{base.converter.ts → metadata-base.mapper.ts} +2 -2
  54. package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +16 -84
  55. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +2 -2
  56. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +4 -9
  57. package/src/libs/feature/editor/src/lib/services/editor.service.ts +16 -27
  58. package/esm2022/libs/api/metadata-converter/src/lib/base.converter.mjs +0 -14
  59. package/esm2022/libs/api/metadata-converter/src/lib/find-converter.mjs +0 -15
  60. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.converter.mjs +0 -52
  61. package/esm2022/libs/api/metadata-converter/src/lib/gn4/index.mjs +0 -4
  62. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/index.mjs +0 -2
  63. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.mjs +0 -123
  64. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.mjs +0 -116
  65. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.mjs +0 -138
  66. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/index.mjs +0 -2
  67. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.mjs +0 -242
  68. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.mjs +0 -18
  69. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.mjs +0 -14
  70. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.mjs +0 -48
  71. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.mjs +0 -18
  72. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.mjs +0 -64
  73. package/libs/api/metadata-converter/src/lib/base.converter.d.ts.map +0 -1
  74. package/libs/api/metadata-converter/src/lib/find-converter.d.ts +0 -3
  75. package/libs/api/metadata-converter/src/lib/find-converter.d.ts.map +0 -1
  76. package/libs/api/metadata-converter/src/lib/gn4/gn4.converter.d.ts.map +0 -1
  77. package/libs/api/metadata-converter/src/lib/gn4/index.d.ts +0 -4
  78. package/libs/api/metadata-converter/src/lib/gn4/index.d.ts.map +0 -1
  79. package/libs/api/metadata-converter/src/lib/iso19115-3/index.d.ts +0 -2
  80. package/libs/api/metadata-converter/src/lib/iso19115-3/index.d.ts.map +0 -1
  81. package/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.d.ts +0 -9
  82. package/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.d.ts.map +0 -1
  83. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts +0 -20
  84. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts.map +0 -1
  85. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts +0 -21
  86. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts.map +0 -1
  87. package/libs/api/metadata-converter/src/lib/iso19139/index.d.ts +0 -2
  88. package/libs/api/metadata-converter/src/lib/iso19139/index.d.ts.map +0 -1
  89. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts +0 -11
  90. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts.map +0 -1
  91. package/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.d.ts +0 -8
  92. package/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.d.ts.map +0 -1
  93. package/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.d.ts.map +0 -1
  94. package/libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.d.ts.map +0 -1
  95. package/libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.d.ts.map +0 -1
  96. package/libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.d.ts.map +0 -1
  97. package/src/libs/api/metadata-converter/src/lib/find-converter.ts +0 -16
  98. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +0 -580
  99. package/src/libs/api/metadata-converter/src/lib/gn4/index.ts +0 -3
  100. package/src/libs/api/metadata-converter/src/lib/iso19115-3/index.ts +0 -1
  101. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +0 -176
  102. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +0 -329
  103. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +0 -513
  104. package/src/libs/api/metadata-converter/src/lib/iso19139/index.ts +0 -1
  105. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +0 -327
  106. package/src/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.ts +0 -20
  107. /package/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/keyword.mapper.d.ts +0 -0
  108. /package/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/role.mapper.d.ts +0 -0
  109. /package/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/status.mapper.d.ts +0 -0
  110. /package/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/update-frequency.mapper.d.ts +0 -0
  111. /package/src/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/keyword.mapper.ts +0 -0
  112. /package/src/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/role.mapper.ts +0 -0
  113. /package/src/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/status.mapper.ts +0 -0
  114. /package/src/libs/api/metadata-converter/src/lib/iso19139/{utils → codelists}/update-frequency.mapper.ts +0 -0
@@ -2,14 +2,14 @@ import { Gn4FieldMapper } from './gn4.field.mapper'
2
2
  import { lastValueFrom } from 'rxjs'
3
3
  import { OrganizationsServiceInterface } from '../../../../../../libs/common/domain/src/lib/organizations.service.interface'
4
4
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
5
- import { BaseConverter } from '../base.converter'
5
+ import { MetadataBaseMapper } from '../metadata-base.mapper'
6
6
  import { Injectable } from '@angular/core'
7
7
  import { Gn4Record } from './types'
8
8
 
9
9
  @Injectable({
10
10
  providedIn: 'root',
11
11
  })
12
- export class Gn4Converter extends BaseConverter<Gn4Record> {
12
+ export class Gn4MetadataMapper extends MetadataBaseMapper<Gn4Record> {
13
13
  constructor(
14
14
  private fieldMapper: Gn4FieldMapper,
15
15
  private orgsService: OrganizationsServiceInterface
@@ -0,0 +1,196 @@
1
+ import {
2
+ CatalogRecord,
3
+ DatasetRecord,
4
+ ServiceRecord,
5
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
6
+ import {
7
+ createDocument,
8
+ createElement,
9
+ getRootElement,
10
+ parseXmlString,
11
+ xmlToString,
12
+ } from '../xml-utils'
13
+ import {
14
+ writeAbstract,
15
+ writeContacts,
16
+ writeDatasetCreated,
17
+ writeDatasetUpdated,
18
+ writeDistributions,
19
+ writeGraphicOverviews,
20
+ writeKeywords,
21
+ writeKind,
22
+ writeLegalConstraints,
23
+ writeLicenses,
24
+ writeLineage,
25
+ writeOnlineResources,
26
+ writeOtherConstraints,
27
+ writeOwnerOrganization,
28
+ writeRecordUpdated,
29
+ writeSecurityConstraints,
30
+ writeSpatialRepresentation,
31
+ writeStatus,
32
+ writeTopics,
33
+ writeTitle,
34
+ writeUniqueIdentifier,
35
+ writeUpdateFrequency,
36
+ } from './write-parts'
37
+ import {
38
+ readAbstract,
39
+ readContacts,
40
+ readDatasetCreated,
41
+ readDatasetUpdated,
42
+ readDistributions,
43
+ readIsoTopics,
44
+ readKeywords,
45
+ readKind,
46
+ readLegalConstraints,
47
+ readLicenses,
48
+ readLineage,
49
+ readOnlineResources,
50
+ readOtherConstraints,
51
+ readOverviews,
52
+ readOwnerOrganization,
53
+ readRecordUpdated,
54
+ readRecordPublished,
55
+ readSecurityConstraints,
56
+ readSpatialExtents,
57
+ readSpatialRepresentation,
58
+ readStatus,
59
+ readTemporalExtents,
60
+ readTitle,
61
+ readUniqueIdentifier,
62
+ readUpdateFrequency,
63
+ } from './read-parts'
64
+ import { isEqual } from '../convert-utils'
65
+
66
+ export function toModel(xml: string): CatalogRecord {
67
+ const doc = parseXmlString(xml)
68
+ const rootEl = getRootElement(doc)
69
+
70
+ const uniqueIdentifier = readUniqueIdentifier(rootEl)
71
+ const kind = readKind(rootEl)
72
+ const ownerOrganization = readOwnerOrganization(rootEl)
73
+ const title = readTitle(rootEl)
74
+ const abstract = readAbstract(rootEl)
75
+ const contacts = readContacts(rootEl)
76
+ const recordUpdated = readRecordUpdated(rootEl)
77
+ const recordCreated = recordUpdated
78
+ const recordPublished = readRecordPublished(rootEl)
79
+ const keywords = readKeywords(rootEl)
80
+ const topics = readIsoTopics(rootEl)
81
+ const legalConstraints = readLegalConstraints(rootEl)
82
+ const otherConstraints = readOtherConstraints(rootEl)
83
+ const securityConstraints = readSecurityConstraints(rootEl)
84
+ const licenses = readLicenses(rootEl)
85
+ const overviews = readOverviews(rootEl)
86
+
87
+ if (kind === 'dataset') {
88
+ const status = readStatus(rootEl)
89
+ const datasetCreated = readDatasetCreated(rootEl)
90
+ const datasetUpdated = readDatasetUpdated(rootEl)
91
+ const spatialRepresentation = readSpatialRepresentation(rootEl)
92
+ const spatialExtents = readSpatialExtents(rootEl)
93
+ const temporalExtents = readTemporalExtents(rootEl)
94
+ const lineage = readLineage(rootEl)
95
+ const distributions = readDistributions(rootEl)
96
+ const updateFrequency = readUpdateFrequency(rootEl)
97
+
98
+ return {
99
+ uniqueIdentifier,
100
+ kind,
101
+ languages: [],
102
+ recordCreated,
103
+ recordUpdated,
104
+ recordPublished,
105
+ status,
106
+ title,
107
+ abstract,
108
+ ownerOrganization,
109
+ contacts,
110
+ contactsForResource: [], // FIXME: is that really useful??
111
+ keywords,
112
+ topics,
113
+ licenses,
114
+ legalConstraints,
115
+ securityConstraints,
116
+ otherConstraints,
117
+ ...(datasetCreated && { datasetCreated }),
118
+ ...(datasetUpdated && { datasetUpdated }),
119
+ lineage,
120
+ ...(spatialRepresentation && { spatialRepresentation }),
121
+ overviews,
122
+ spatialExtents,
123
+ temporalExtents,
124
+ distributions,
125
+ updateFrequency,
126
+ } as DatasetRecord
127
+ } else {
128
+ const onlineResources = readOnlineResources(rootEl)
129
+ return {
130
+ uniqueIdentifier,
131
+ kind,
132
+ languages: [],
133
+ recordCreated,
134
+ recordUpdated,
135
+ recordPublished,
136
+ title,
137
+ abstract,
138
+ ownerOrganization,
139
+ contacts,
140
+ keywords,
141
+ topics,
142
+ licenses,
143
+ legalConstraints,
144
+ securityConstraints,
145
+ otherConstraints,
146
+ overviews,
147
+ onlineResources,
148
+ } as ServiceRecord
149
+ }
150
+ }
151
+
152
+ export function toXml(record: CatalogRecord, originalXml?: string): string {
153
+ const originalDoc = originalXml ? parseXmlString(originalXml) : null
154
+ const originalRecord = originalXml ? toModel(originalXml) : null
155
+ const rootEl = originalDoc
156
+ ? getRootElement(originalDoc)
157
+ : createElement('gmd:MD_Metadata')()
158
+
159
+ function fieldChanged(name: string) {
160
+ return originalRecord !== null
161
+ ? !isEqual(record[name], originalRecord[name])
162
+ : true
163
+ }
164
+
165
+ writeUniqueIdentifier(record, rootEl)
166
+ writeKind(record, rootEl)
167
+ fieldChanged('ownerOrganization') && writeOwnerOrganization(record, rootEl)
168
+ fieldChanged('recordUpdated') && writeRecordUpdated(record, rootEl)
169
+ writeTitle(record, rootEl)
170
+ writeAbstract(record, rootEl)
171
+ fieldChanged('contacts') && writeContacts(record, rootEl)
172
+ fieldChanged('keywords') && writeKeywords(record, rootEl)
173
+ fieldChanged('topics') && writeTopics(record, rootEl)
174
+ fieldChanged('legalConstraints') && writeLegalConstraints(record, rootEl)
175
+ fieldChanged('securityConstraints') &&
176
+ writeSecurityConstraints(record, rootEl)
177
+ fieldChanged('licenses') && writeLicenses(record, rootEl)
178
+ fieldChanged('otherConstraints') && writeOtherConstraints(record, rootEl)
179
+
180
+ if (record.kind === 'dataset') {
181
+ writeStatus(record, rootEl)
182
+ fieldChanged('updateFrequency') && writeUpdateFrequency(record, rootEl)
183
+ fieldChanged('datasetCreated') && writeDatasetCreated(record, rootEl)
184
+ fieldChanged('datasetUpdated') && writeDatasetUpdated(record, rootEl)
185
+ fieldChanged('spatialRepresentation') &&
186
+ writeSpatialRepresentation(record, rootEl)
187
+ fieldChanged('overviews') && writeGraphicOverviews(record, rootEl)
188
+ fieldChanged('distributions') && writeDistributions(record, rootEl)
189
+ writeLineage(record, rootEl)
190
+ } else {
191
+ fieldChanged('onlineResources') && writeOnlineResources(record, rootEl)
192
+ }
193
+
194
+ const newDocument = createDocument(rootEl)
195
+ return xmlToString(newDocument)
196
+ }
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  Constraint,
3
3
  DatasetDistribution,
4
+ DatasetSpatialExtent,
5
+ DatasetTemporalExtent,
4
6
  GraphicOverview,
5
7
  Individual,
6
8
  Keyword,
@@ -14,8 +16,8 @@ import {
14
16
  UpdateFrequency,
15
17
  UpdateFrequencyCustom,
16
18
  } from '../../../../../../libs/common/domain/src/lib/model/record'
17
- import { getStatusFromStatusCode } from './utils/status.mapper'
18
- import { getUpdateFrequencyFromFrequencyCode } from './utils/update-frequency.mapper'
19
+ import { getStatusFromStatusCode } from './codelists/status.mapper'
20
+ import { getUpdateFrequencyFromFrequencyCode } from './codelists/update-frequency.mapper'
19
21
  import {
20
22
  findChildElement,
21
23
  findChildrenElement,
@@ -37,15 +39,11 @@ import {
37
39
  mapArray,
38
40
  pipe,
39
41
  } from '../function-utils'
40
- import { getRoleFromRoleCode } from './utils/role.mapper'
42
+ import { getRoleFromRoleCode } from './codelists/role.mapper'
41
43
  import { matchMimeType, matchProtocol } from '../common/distribution.mapper'
42
- import { getKeywordTypeFromKeywordTypeCode } from './utils/keyword.mapper'
43
- import { fullNameToParts } from './utils/individual-name'
44
+ import { getKeywordTypeFromKeywordTypeCode } from './codelists/keyword.mapper'
44
45
 
45
- export function extractCharacterString(): ChainableFunction<
46
- XmlElement,
47
- string
48
- > {
46
+ function extractCharacterString(): ChainableFunction<XmlElement, string> {
49
47
  return pipe(
50
48
  fallback(
51
49
  findChildElement('gco:CharacterString', false),
@@ -55,7 +53,7 @@ export function extractCharacterString(): ChainableFunction<
55
53
  )
56
54
  }
57
55
 
58
- export function extractDateTime(): ChainableFunction<XmlElement, Date> {
56
+ function extractDateTime(): ChainableFunction<XmlElement, Date> {
59
57
  return pipe(
60
58
  fallback(
61
59
  findChildElement('gco:DateTime', false),
@@ -66,7 +64,7 @@ export function extractDateTime(): ChainableFunction<XmlElement, Date> {
66
64
  )
67
65
  }
68
66
 
69
- export function extractUrl(): ChainableFunction<XmlElement, URL> {
67
+ function extractUrl(): ChainableFunction<XmlElement, URL> {
70
68
  const getUrl = pipe(findChildElement('gmd:URL', false), readText())
71
69
  const getCharacterString = pipe(
72
70
  findChildElement('gco:CharacterString', false),
@@ -88,12 +86,12 @@ export function extractUrl(): ChainableFunction<XmlElement, URL> {
88
86
  )
89
87
  }
90
88
 
91
- export function extractMandatoryUrl() {
89
+ function extractMandatoryUrl() {
92
90
  return fallback(extractUrl(), () => new URL('http://missing'))
93
91
  }
94
92
 
95
93
  // from gmd:role
96
- export function extractRole(): ChainableFunction<XmlElement, Role> {
94
+ function extractRole(): ChainableFunction<XmlElement, Role> {
97
95
  return pipe(
98
96
  findChildElement('gmd:CI_RoleCode'),
99
97
  readAttribute('codeListValue'),
@@ -102,10 +100,7 @@ export function extractRole(): ChainableFunction<XmlElement, Role> {
102
100
  }
103
101
 
104
102
  // from gmd:CI_ResponsibleParty
105
- export function extractOrganization(): ChainableFunction<
106
- XmlElement,
107
- Organization
108
- > {
103
+ function extractOrganization(): ChainableFunction<XmlElement, Organization> {
109
104
  const getUrl = pipe(
110
105
  findNestedElements(
111
106
  'gmd:contactInfo',
@@ -133,7 +128,10 @@ export function extractOrganization(): ChainableFunction<
133
128
  }
134
129
 
135
130
  // from gmd:CI_ResponsibleParty
136
- export function extractIndividual(): ChainableFunction<XmlElement, Individual> {
131
+ function extractIndividuals(): ChainableFunction<
132
+ XmlElement,
133
+ Array<Individual>
134
+ > {
137
135
  const getRole = pipe(findChildElement('gmd:role'), extractRole())
138
136
  const getPosition = pipe(
139
137
  findChildElement('gmd:positionName'),
@@ -144,70 +142,40 @@ export function extractIndividual(): ChainableFunction<XmlElement, Individual> {
144
142
  extractCharacterString(),
145
143
  map((fullName) => {
146
144
  if (!fullName) return []
147
- return fullNameToParts(fullName)
145
+ const parts = fullName.split(/\s+/)
146
+ if (!parts.length) return [fullName, null]
147
+ const first = parts.shift()
148
+ return [first, parts.join(' ')]
148
149
  })
149
150
  )
150
151
  const getOrganization = extractOrganization()
151
- const getContactRoot = findNestedElement('gmd:contactInfo', 'gmd:CI_Contact')
152
152
  const getEmail = pipe(
153
- getContactRoot,
154
153
  findChildElement('gmd:electronicMailAddress'),
155
154
  extractCharacterString(),
156
155
  map((email) => (email === null ? 'missing@missing.com' : email))
157
156
  )
158
- const getAddress = pipe(
159
- getContactRoot,
160
- findNestedElement('gmd:address', 'gmd:CI_Address'),
161
- combine(
162
- pipe(
163
- findChildElement('gmd:deliveryPoint', false),
164
- extractCharacterString()
165
- ),
166
- pipe(findChildElement('gmd:city', false), extractCharacterString()),
167
- pipe(findChildElement('gmd:postalCode', false), extractCharacterString()),
168
- pipe(findChildElement('gmd:country', false), extractCharacterString())
169
- ),
170
- map((parts) => parts.filter((p) => !!p).join(', '))
171
- )
172
- const getPhone = pipe(
173
- getContactRoot,
174
- findNestedElement('gmd:phone', 'gmd:CI_Telephone', 'gmd:voice'),
175
- extractCharacterString()
176
- )
177
157
  return pipe(
178
158
  combine(
179
159
  getRole,
180
160
  getPosition,
181
161
  getNameParts,
182
162
  getOrganization,
183
- getEmail,
184
- getAddress,
185
- getPhone
163
+ pipe(findChildrenElement('gmd:contactInfo'), mapArray(getEmail))
186
164
  ),
187
- map(
188
- ([
189
- role,
190
- position,
191
- [firstName, lastName],
192
- organization,
193
- email,
194
- address,
195
- phone,
196
- ]) => ({
165
+ map(([role, position, [firstName, lastName], organization, emails]) =>
166
+ emails.map((email) => ({
197
167
  email,
198
168
  role,
199
169
  organization,
200
170
  ...(position && { position }),
201
171
  ...(firstName && { firstName }),
202
172
  ...(lastName && { lastName }),
203
- ...(address && { address }),
204
- ...(phone && { phone }),
205
- })
173
+ }))
206
174
  )
207
175
  )
208
176
  }
209
177
 
210
- export function extractStatus(): ChainableFunction<XmlElement, RecordStatus> {
178
+ function extractStatus(): ChainableFunction<XmlElement, RecordStatus> {
211
179
  return pipe(
212
180
  findChildElement('gmd:MD_ProgressCode'),
213
181
  readAttribute('codeListValue'),
@@ -216,7 +184,7 @@ export function extractStatus(): ChainableFunction<XmlElement, RecordStatus> {
216
184
  }
217
185
 
218
186
  // from gmd:resourceConstraints
219
- export function extractLegalConstraints(): ChainableFunction<
187
+ function extractLegalConstraints(): ChainableFunction<
220
188
  XmlElement,
221
189
  Array<Constraint>
222
190
  > {
@@ -246,7 +214,7 @@ export function extractLegalConstraints(): ChainableFunction<
246
214
  }
247
215
 
248
216
  // from gmd:resourceConstraints
249
- export function extractSecurityConstraints(): ChainableFunction<
217
+ function extractSecurityConstraints(): ChainableFunction<
250
218
  XmlElement,
251
219
  Array<Constraint>
252
220
  > {
@@ -262,7 +230,7 @@ export function extractSecurityConstraints(): ChainableFunction<
262
230
  }
263
231
 
264
232
  // from gmd:resourceConstraints
265
- export function extractOtherConstraints(): ChainableFunction<
233
+ function extractOtherConstraints(): ChainableFunction<
266
234
  XmlElement,
267
235
  Array<Constraint>
268
236
  > {
@@ -278,10 +246,7 @@ export function extractOtherConstraints(): ChainableFunction<
278
246
  }
279
247
 
280
248
  // from gmd:resourceConstraints
281
- export function extractLicenses(): ChainableFunction<
282
- XmlElement,
283
- Array<Constraint>
284
- > {
249
+ function extractLicenses(): ChainableFunction<XmlElement, Array<Constraint>> {
285
250
  return pipe(
286
251
  findChildrenElement('gmd:MD_LegalConstraints', false),
287
252
  filterArray(
@@ -307,20 +272,18 @@ export function extractLicenses(): ChainableFunction<
307
272
  )
308
273
  }
309
274
 
310
- const getMimeType = pipe(
311
- findParent('gmd:MD_Distribution'),
312
- findNestedElement('gmd:distributionFormat', 'gmd:MD_Format', 'gmd:name'),
313
- extractCharacterString(),
314
- map(matchMimeType)
315
- )
275
+ // from gmd:MD_Distribution
276
+ function extractDatasetDistributions(): ChainableFunction<
277
+ XmlElement,
278
+ DatasetDistribution[]
279
+ > {
280
+ const getFormat = pipe(
281
+ findParent('gmd:MD_Distribution'),
282
+ findNestedElement('gmd:distributionFormat', 'gmd:MD_Format', 'gmd:name'),
283
+ extractCharacterString(),
284
+ map(matchMimeType)
285
+ )
316
286
 
317
- /**
318
- * Extract distributions from a MD_Distribution element
319
- * @param getMimeTypeFn This function starts from a gmd:transferOptions element
320
- */
321
- export function extractDatasetDistributions(
322
- getMimeTypeFn: ChainableFunction<XmlElement, string>
323
- ): ChainableFunction<XmlElement, DatasetDistribution[]> {
324
287
  const getUrl = pipe(findChildElement('gmd:linkage'), extractMandatoryUrl())
325
288
  const getProtocolStr = pipe(
326
289
  findChildElement('gmd:protocol'),
@@ -363,11 +326,11 @@ export function extractDatasetDistributions(
363
326
  getUrl,
364
327
  getName,
365
328
  getDescription,
366
- getMimeTypeFn
329
+ getFormat
367
330
  )
368
331
  ),
369
332
  mapArray(
370
- ([isService, isDownload, protocol, url, name, description, mimeType]) => {
333
+ ([isService, isDownload, protocol, url, name, description, format]) => {
371
334
  if (isService) {
372
335
  const hasIdentifier = protocol === 'wms' || protocol === 'wfs'
373
336
  return {
@@ -379,6 +342,7 @@ export function extractDatasetDistributions(
379
342
  ...(description && { description }),
380
343
  }
381
344
  } else if (isDownload) {
345
+ const mimeType = format
382
346
  return {
383
347
  type: 'download',
384
348
  url: url,
@@ -399,7 +363,7 @@ export function extractDatasetDistributions(
399
363
  )
400
364
  }
401
365
 
402
- export function getUpdateFrequencyFromCustomPeriod(
366
+ function getUpdateFrequencyFromCustomPeriod(
403
367
  isoPeriod: string
404
368
  ): UpdateFrequencyCustom {
405
369
  if (!isoPeriod) return null
@@ -451,7 +415,7 @@ export function getUpdateFrequencyFromCustomPeriod(
451
415
  }
452
416
 
453
417
  // from gmd:MD_MaintenanceInformation
454
- export function extractUpdateFrequency(): ChainableFunction<
418
+ function extractUpdateFrequency(): ChainableFunction<
455
419
  XmlElement,
456
420
  UpdateFrequency
457
421
  > {
@@ -475,24 +439,18 @@ export function extractUpdateFrequency(): ChainableFunction<
475
439
 
476
440
  /**
477
441
  * Looks for srv:SV_ServiceIdentification or gmd:MD_DataIdentification element
478
- * Will find the first one that exists, not reading the type of the record
479
- * (this allows using this function in other similar schemas)
442
+ * depending on record type
480
443
  */
481
- export function findIdentification() {
482
- return pipe(
483
- findChildElement('gmd:identificationInfo', false),
484
- combine(
485
- findChildElement('gmd:MD_DataIdentification', false),
486
- findChildElement('srv:SV_ServiceIdentification', false)
487
- ),
488
- filterArray((el) => el !== null),
489
- getAtIndex(0)
490
- )
444
+ function findIdentification() {
445
+ return (rootEl: XmlElement) => {
446
+ const kind = readKind(rootEl)
447
+ let eltName = 'gmd:MD_DataIdentification'
448
+ if (kind === 'service') eltName = 'srv:SV_ServiceIdentification'
449
+ return findNestedElement('gmd:identificationInfo', eltName)(rootEl)
450
+ }
491
451
  }
492
452
 
493
- export function extractIdentificationDate(
494
- type: 'creation' | 'revision' | 'publication'
495
- ) {
453
+ function extractCitationDate(type: 'creation' | 'revision' | 'publication') {
496
454
  return pipe(
497
455
  findIdentification(),
498
456
  findNestedElements('gmd:citation', 'gmd:CI_Citation', 'gmd:date'),
@@ -515,7 +473,7 @@ export function extractIdentificationDate(
515
473
  )
516
474
  }
517
475
 
518
- export function getSpatialRepresentationFromCode(
476
+ function getSpatialRepresentationFromCode(
519
477
  spatialRepresentationCode: string
520
478
  ): SpatialRepresentationType | null {
521
479
  switch (spatialRepresentationCode) {
@@ -555,19 +513,11 @@ export function readOwnerOrganization(rootEl: XmlElement): Organization {
555
513
  )(rootEl)
556
514
  }
557
515
 
558
- export function readResourceUpdated(rootEl: XmlElement): Date {
559
- return extractIdentificationDate('revision')(rootEl)
560
- }
561
-
562
- export function readResourceCreated(rootEl: XmlElement): Date {
563
- return extractIdentificationDate('creation')(rootEl)
564
- }
565
-
566
- export function readResourcePublished(rootEl: XmlElement): Date {
567
- return extractIdentificationDate('publication')(rootEl)
516
+ export function readRecordUpdated(rootEl: XmlElement): Date {
517
+ return pipe(findChildElement('gmd:dateStamp'), extractDateTime())(rootEl)
568
518
  }
569
519
 
570
- export function readRecordUpdated(rootEl: XmlElement): Date {
520
+ export function readRecordPublished(rootEl: XmlElement): Date {
571
521
  return pipe(findChildElement('gmd:dateStamp'), extractDateTime())(rootEl)
572
522
  }
573
523
 
@@ -587,29 +537,30 @@ export function readAbstract(rootEl: XmlElement): string {
587
537
  )(rootEl)
588
538
  }
589
539
 
590
- export function readContacts(rootEl: XmlElement): Individual[] {
591
- return pipe(
592
- findChildrenElement('gmd:contact', false),
593
- mapArray(findChildElement('gmd:CI_ResponsibleParty', false)),
594
- mapArray(extractIndividual())
595
- )(rootEl)
540
+ export function readDatasetCreated(rootEl: XmlElement): Date {
541
+ return extractCitationDate('creation')(rootEl)
596
542
  }
597
543
 
598
- export function readContactsForResource(rootEl: XmlElement): Individual[] {
544
+ export function readDatasetUpdated(rootEl: XmlElement): Date {
545
+ return extractCitationDate('revision')(rootEl)
546
+ }
547
+
548
+ export function readContacts(rootEl: XmlElement): Individual[] {
599
549
  return pipe(
600
550
  findIdentification(),
601
551
  combine(
602
- findChildrenElement('gmd:contact', false),
603
- findChildrenElement('gmd:pointOfContact', false)
552
+ findChildrenElement('gmd:contact'),
553
+ findChildrenElement('gmd:pointOfContact')
604
554
  ),
605
555
  flattenArray(),
606
556
  mapArray(findChildElement('gmd:CI_ResponsibleParty', false)),
607
- mapArray(extractIndividual())
557
+ mapArray(extractIndividuals()),
558
+ flattenArray()
608
559
  )(rootEl)
609
560
  }
610
561
 
611
562
  // from gmd:thesaurusName
612
- export function readThesaurus(rootEl: XmlElement): KeywordThesaurus {
563
+ function readThesaurus(rootEl: XmlElement): KeywordThesaurus {
613
564
  if (!rootEl) return null
614
565
 
615
566
  const findIdentifier = findNestedElement(
@@ -632,7 +583,7 @@ export function readThesaurus(rootEl: XmlElement): KeywordThesaurus {
632
583
  }
633
584
 
634
585
  // from gmd:MD_Keywords
635
- export function readKeywordGroup(rootEl: XmlElement): Keyword[] {
586
+ function readKeywordGroup(rootEl: XmlElement): Keyword[] {
636
587
  const type = pipe(
637
588
  findChildrenElement('gmd:MD_KeywordTypeCode'),
638
589
  mapArray(readAttribute('codeListValue')),
@@ -750,6 +701,16 @@ export function readOverviews(rootEl: XmlElement): GraphicOverview[] {
750
701
  )(rootEl)
751
702
  }
752
703
 
704
+ export function readSpatialExtents(rootEl: XmlElement): DatasetSpatialExtent[] {
705
+ return [] // TODO
706
+ }
707
+
708
+ export function readTemporalExtents(
709
+ rootEl: XmlElement
710
+ ): DatasetTemporalExtent[] {
711
+ return [] // TODO
712
+ }
713
+
753
714
  export function readLineage(rootEl: XmlElement): string {
754
715
  return pipe(
755
716
  findNestedElement(
@@ -766,7 +727,7 @@ export function readLineage(rootEl: XmlElement): string {
766
727
  export function readDistributions(rootEl: XmlElement): DatasetDistribution[] {
767
728
  return pipe(
768
729
  findNestedElements('gmd:distributionInfo', 'gmd:MD_Distribution'),
769
- mapArray(extractDatasetDistributions(getMimeType)),
730
+ mapArray(extractDatasetDistributions()),
770
731
  flattenArray()
771
732
  )(rootEl)
772
733
  }