geonetwork-ui 2.3.0-dev.2c3530dc → 2.3.0-dev.376e0e90

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/base.converter.mjs +14 -0
  3. package/esm2022/libs/api/metadata-converter/src/lib/find-converter.mjs +15 -0
  4. package/esm2022/libs/api/metadata-converter/src/lib/gn4/atomic-operations.mjs +3 -3
  5. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.converter.mjs +52 -0
  6. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +3 -3
  7. package/esm2022/libs/api/metadata-converter/src/lib/gn4/index.mjs +4 -0
  8. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/index.mjs +2 -0
  9. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.mjs +123 -0
  10. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.mjs +116 -0
  11. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.mjs +138 -0
  12. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/index.mjs +2 -0
  13. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.mjs +242 -0
  14. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +58 -62
  15. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.mjs +18 -0
  16. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.mjs +14 -0
  17. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.mjs +48 -0
  18. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.mjs +18 -0
  19. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.mjs +64 -0
  20. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +75 -58
  21. package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +76 -14
  22. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +4 -4
  23. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  24. package/esm2022/libs/feature/editor/src/lib/services/editor.service.mjs +8 -8
  25. package/fesm2022/geonetwork-ui.mjs +822 -245
  26. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  27. package/libs/api/metadata-converter/src/index.d.ts +4 -4
  28. package/libs/api/metadata-converter/src/index.d.ts.map +1 -1
  29. package/libs/api/metadata-converter/src/lib/{metadata-base.mapper.d.ts → base.converter.d.ts} +3 -3
  30. package/libs/api/metadata-converter/src/lib/base.converter.d.ts.map +1 -0
  31. package/libs/api/metadata-converter/src/lib/find-converter.d.ts +3 -0
  32. package/libs/api/metadata-converter/src/lib/find-converter.d.ts.map +1 -0
  33. package/libs/api/metadata-converter/src/lib/gn4/{gn4.metadata.mapper.d.ts → gn4.converter.d.ts} +5 -5
  34. package/libs/api/metadata-converter/src/lib/gn4/gn4.converter.d.ts.map +1 -0
  35. package/libs/api/metadata-converter/src/lib/gn4/index.d.ts +4 -0
  36. package/libs/api/metadata-converter/src/lib/gn4/index.d.ts.map +1 -0
  37. package/libs/api/metadata-converter/src/lib/iso19115-3/index.d.ts +2 -0
  38. package/libs/api/metadata-converter/src/lib/iso19115-3/index.d.ts.map +1 -0
  39. package/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.d.ts +9 -0
  40. package/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.d.ts.map +1 -0
  41. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts +20 -0
  42. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts.map +1 -0
  43. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts +21 -0
  44. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts.map +1 -0
  45. package/libs/api/metadata-converter/src/lib/iso19139/index.d.ts +2 -0
  46. package/libs/api/metadata-converter/src/lib/iso19139/index.d.ts.map +1 -0
  47. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts +11 -0
  48. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts.map +1 -0
  49. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +34 -6
  50. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  51. package/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.d.ts +8 -0
  52. package/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.d.ts.map +1 -0
  53. package/libs/api/metadata-converter/src/lib/iso19139/utils/keyword.mapper.d.ts.map +1 -0
  54. package/libs/api/metadata-converter/src/lib/iso19139/utils/role.mapper.d.ts.map +1 -0
  55. package/libs/api/metadata-converter/src/lib/iso19139/utils/status.mapper.d.ts.map +1 -0
  56. package/libs/api/metadata-converter/src/lib/iso19139/utils/update-frequency.mapper.d.ts.map +1 -0
  57. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +39 -3
  58. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  59. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts +14 -1
  60. package/libs/api/metadata-converter/src/lib/xml-utils.d.ts.map +1 -1
  61. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +2 -2
  62. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  63. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +6 -4
  64. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  65. package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
  66. package/package.json +1 -1
  67. package/src/libs/api/metadata-converter/src/index.ts +4 -4
  68. package/src/libs/api/metadata-converter/src/lib/{metadata-base.mapper.ts → base.converter.ts} +2 -2
  69. package/src/libs/api/metadata-converter/src/lib/find-converter.ts +16 -0
  70. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +32 -5
  71. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +11 -4
  72. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +33 -7
  73. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +580 -0
  74. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +2 -2
  75. package/src/libs/api/metadata-converter/src/lib/gn4/{gn4.metadata.mapper.ts → gn4.converter.ts} +2 -2
  76. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +2 -2
  77. package/src/libs/api/metadata-converter/src/lib/gn4/index.ts +3 -0
  78. package/src/libs/api/metadata-converter/src/lib/iso19115-3/index.ts +1 -0
  79. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +176 -0
  80. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +329 -0
  81. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +513 -0
  82. package/src/libs/api/metadata-converter/src/lib/iso19139/index.ts +1 -0
  83. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +327 -0
  84. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +121 -82
  85. package/src/libs/api/metadata-converter/src/lib/iso19139/utils/individual-name.ts +20 -0
  86. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +175 -95
  87. package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +84 -16
  88. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +2 -2
  89. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +9 -4
  90. package/src/libs/feature/editor/src/lib/services/editor.service.ts +27 -16
  91. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.mjs +0 -52
  92. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.mjs +0 -14
  93. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.mjs +0 -48
  94. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.mjs +0 -18
  95. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.mjs +0 -64
  96. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/converter.mjs +0 -130
  97. package/esm2022/libs/api/metadata-converter/src/lib/metadata-base.mapper.mjs +0 -14
  98. package/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.d.ts.map +0 -1
  99. package/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.d.ts.map +0 -1
  100. package/libs/api/metadata-converter/src/lib/iso19139/codelists/role.mapper.d.ts.map +0 -1
  101. package/libs/api/metadata-converter/src/lib/iso19139/codelists/status.mapper.d.ts.map +0 -1
  102. package/libs/api/metadata-converter/src/lib/iso19139/codelists/update-frequency.mapper.d.ts.map +0 -1
  103. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts +0 -4
  104. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts.map +0 -1
  105. package/libs/api/metadata-converter/src/lib/metadata-base.mapper.d.ts.map +0 -1
  106. package/src/libs/api/metadata-converter/src/lib/iso19139/converter.ts +0 -196
  107. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/keyword.mapper.d.ts +0 -0
  108. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/role.mapper.d.ts +0 -0
  109. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/status.mapper.d.ts +0 -0
  110. /package/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/update-frequency.mapper.d.ts +0 -0
  111. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/keyword.mapper.ts +0 -0
  112. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/role.mapper.ts +0 -0
  113. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/status.mapper.ts +0 -0
  114. /package/src/libs/api/metadata-converter/src/lib/iso19139/{codelists → utils}/update-frequency.mapper.ts +0 -0
@@ -0,0 +1,176 @@
1
+ import { Iso19139Converter } from '../iso19139'
2
+ import {
3
+ readContacts,
4
+ readDistributions,
5
+ readKind,
6
+ readLandingPage,
7
+ readLineage,
8
+ readOwnerOrganization,
9
+ readRecordCreated,
10
+ readRecordPublished,
11
+ readRecordUpdated,
12
+ readResourceContacts,
13
+ readUniqueIdentifier,
14
+ } from './read-parts'
15
+ import {
16
+ writeContacts,
17
+ writeContactsForResource,
18
+ writeDistributions,
19
+ writeKind,
20
+ writeLandingPage,
21
+ writeLineage,
22
+ writeOwnerOrganization,
23
+ writeRecordCreated,
24
+ writeRecordPublished,
25
+ writeRecordUpdated,
26
+ writeResourceCreated,
27
+ writeResourcePublished,
28
+ writeResourceUpdated,
29
+ writeSpatialRepresentation,
30
+ writeStatus,
31
+ writeUniqueIdentifier,
32
+ } from './write-parts'
33
+ import { XmlElement } from '@rgrove/parse-xml'
34
+ import { renameElements } from '../xml-utils'
35
+ import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
36
+
37
+ export class Iso191153Converter extends Iso19139Converter {
38
+ constructor() {
39
+ super()
40
+
41
+ this.readers['uniqueIdentifier'] = readUniqueIdentifier
42
+ this.readers['kind'] = readKind
43
+ this.readers['recordUpdated'] = readRecordUpdated
44
+ this.readers['recordCreated'] = readRecordCreated
45
+ this.readers['recordPublished'] = readRecordPublished
46
+ this.readers['contacts'] = readContacts
47
+ this.readers['contactsForResource'] = readResourceContacts
48
+ this.readers['ownerOrganization'] = readOwnerOrganization
49
+ this.readers['landingPage'] = readLandingPage
50
+ this.readers['lineage'] = readLineage
51
+ this.readers['distributions'] = readDistributions
52
+
53
+ this.writers['uniqueIdentifier'] = writeUniqueIdentifier
54
+ this.writers['kind'] = writeKind
55
+ this.writers['recordUpdated'] = writeRecordUpdated
56
+ this.writers['recordCreated'] = writeRecordCreated
57
+ this.writers['recordPublished'] = writeRecordPublished
58
+ this.writers['resourceUpdated'] = writeResourceUpdated
59
+ this.writers['resourceCreated'] = writeResourceCreated
60
+ this.writers['resourcePublished'] = writeResourcePublished
61
+ this.writers['contacts'] = writeContacts
62
+ this.writers['contactsForResource'] = writeContactsForResource
63
+ this.writers['ownerOrganization'] = writeOwnerOrganization
64
+ this.writers['landingPage'] = writeLandingPage
65
+ this.writers['lineage'] = writeLineage
66
+ this.writers['distributions'] = writeDistributions
67
+ this.writers['status'] = writeStatus
68
+ this.writers['spatialRepresentation'] = writeSpatialRepresentation
69
+ }
70
+
71
+ beforeDocumentCreation(rootEl: XmlElement) {
72
+ renameElements(rootEl, {
73
+ gmd: 'mdb',
74
+ 'gmd:characterEncoding': 'lan:characterEncoding',
75
+ 'gmd:MD_CharacterSetCode': 'lan:MD_CharacterSetCode',
76
+ 'gmd:MD_DataIdentification': 'mri:MD_DataIdentification',
77
+ 'gmd:citation': 'mri:citation',
78
+ 'gmd:abstract': 'mri:abstract',
79
+ 'gmd:title': 'cit:title',
80
+ 'gmd:CI_Citation': 'cit:CI_Citation',
81
+ 'gmx:Anchor': 'gcx:Anchor',
82
+
83
+ // languages
84
+ 'gmd:PT_Locale': 'lan:PT_Locale',
85
+ 'gmd:languageCode': 'lan:languageCode',
86
+ 'gmd:LanguageCode': 'lan:LanguageCode',
87
+
88
+ // status
89
+ 'gmd:status': 'mri:status',
90
+ 'gmd:MD_ProgressCode': 'mri:MD_ProgressCode',
91
+
92
+ // dates
93
+ 'gmd:date': 'cit:date',
94
+ 'gmd:CI_Date': 'cit:CI_Date',
95
+ 'gmd:dateType': 'cit:dateType',
96
+ 'gmd:CI_DateTypeCode': 'cit:CI_DateTypeCode',
97
+
98
+ // contacts
99
+ 'gmd:CI_Responsibility': 'cit:CI_Responsibility',
100
+ 'gmd:role': 'cit:role',
101
+ 'gmd:CI_RoleCode': 'cit:CI_RoleCode',
102
+
103
+ // keywords
104
+ 'gmd:descriptiveKeywords': 'mri:descriptiveKeywords',
105
+ 'gmd:MD_Keywords': 'mri:MD_Keywords',
106
+ 'gmd:type': 'mri:type',
107
+ 'gmd:MD_KeywordTypeCode': 'mri:MD_KeywordTypeCode',
108
+ 'gmd:thesaurusName': 'mri:thesaurusName',
109
+ 'gmd:keyword': 'mri:keyword',
110
+ 'gmd:identifier': 'cit:identifier',
111
+ 'gmd:MD_Identifier': 'mcc:MD_Identifier',
112
+ 'gmd:code': 'mcc:code',
113
+
114
+ // distributions
115
+ 'gmd:MD_Distribution': 'mrd:MD_Distribution',
116
+ 'gmd:transferOptions': 'mrd:transferOptions',
117
+ 'gmd:MD_DigitalTransferOptions': 'mrd:MD_DigitalTransferOptions',
118
+ 'gmd:onLine': 'mrd:onLine',
119
+ 'gmd:distributionFormat': 'mrd:distributionFormat',
120
+ 'gmd:MD_Format': 'mrd:MD_Format',
121
+ 'gmd:CI_OnlineResource': 'cit:CI_OnlineResource',
122
+ 'gmd:linkage': 'cit:linkage',
123
+ 'gmd:name': 'cit:name',
124
+ 'gmd:description': 'cit:description',
125
+ 'gmd:CI_OnLineFunctionCode': 'cit:CI_OnLineFunctionCode',
126
+ 'gmd:function': 'cit:function',
127
+ 'gmd:protocol': 'cit:protocol',
128
+
129
+ // topic
130
+ 'gmd:topicCategory': 'mri:topicCategory',
131
+ 'gmd:MD_TopicCategoryCode': 'mri:MD_TopicCategoryCode',
132
+
133
+ // update frequency
134
+ 'gmd:resourceMaintenance': 'mri:resourceMaintenance',
135
+ 'gmd:MD_MaintenanceInformation': 'mmi:MD_MaintenanceInformation',
136
+ 'gmd:userDefinedMaintenanceFrequency':
137
+ 'mmi:userDefinedMaintenanceFrequency',
138
+ 'gts:TM_PeriodDuration': 'gco:TM_PeriodDuration',
139
+
140
+ // constraints
141
+ 'gmd:resourceConstraints': 'mri:resourceConstraints',
142
+ 'gmd:MD_Constraints': 'mco:MD_Constraints',
143
+ 'gmd:MD_LegalConstraints': 'mco:MD_LegalConstraints',
144
+ 'gmd:MD_SecurityConstraints': 'mco:MD_SecurityConstraints',
145
+ 'gmd:useLimitation': 'mco:useLimitation',
146
+ 'gmd:useConstraints': 'mco:useConstraints',
147
+ 'gmd:accessConstraints': 'mco:accessConstraints',
148
+ 'gmd:otherConstraints': 'mco:otherConstraints',
149
+ 'gmd:MD_RestrictionCode': 'mco:MD_RestrictionCode',
150
+ 'gmd:classification': 'mco:classification',
151
+ 'gmd:MD_ClassificationCode': 'mco:MD_ClassificationCode',
152
+
153
+ // overviews
154
+ 'gmd:graphicOverview': 'mri:graphicOverview',
155
+ 'gmd:MD_BrowseGraphic': 'mcc:MD_BrowseGraphic',
156
+ 'gmd:fileName': 'mcc:fileName',
157
+ 'gmd:fileDescription': 'mcc:fileDescription',
158
+
159
+ // no more URL elements
160
+ 'gmd:URL': 'gco:CharacterString',
161
+ })
162
+ }
163
+
164
+ async writeRecord(
165
+ record: CatalogRecord,
166
+ reference?: string
167
+ ): Promise<string> {
168
+ let result = await super.writeRecord(record, reference)
169
+ // fix gco namespace definition (changes between iso19139 and iso19115-3
170
+ result = result.replace(
171
+ '"http://www.isotc211.org/2005/gco"',
172
+ '"http://standards.iso.org/iso/19115/-3/gco/1.0"'
173
+ )
174
+ return result
175
+ }
176
+ }
@@ -0,0 +1,329 @@
1
+ import {
2
+ findChildElement,
3
+ findChildrenElement,
4
+ findNestedElement,
5
+ findNestedElements,
6
+ findParent,
7
+ readAttribute,
8
+ XmlElement,
9
+ } from '../xml-utils'
10
+ import {
11
+ ChainableFunction,
12
+ combine,
13
+ filterArray,
14
+ flattenArray,
15
+ getAtIndex,
16
+ map,
17
+ mapArray,
18
+ pipe,
19
+ } from '../function-utils'
20
+ import {
21
+ extractCharacterString,
22
+ extractDatasetDistributions,
23
+ extractDateTime,
24
+ extractRole,
25
+ extractUrl,
26
+ findIdentification,
27
+ } from '../iso19139/read-parts'
28
+ import {
29
+ DatasetDistribution,
30
+ Individual,
31
+ Organization,
32
+ RecordKind,
33
+ Role,
34
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
35
+ import { matchMimeType } from '../common/distribution.mapper'
36
+ import { fullNameToParts } from '../iso19139/utils/individual-name'
37
+
38
+ export function readKind(rootEl: XmlElement): RecordKind {
39
+ return pipe(
40
+ findNestedElement(
41
+ 'mdb:metadataScope',
42
+ 'mdb:MD_MetadataScope',
43
+ 'mdb:resourceScope',
44
+ 'mcc:MD_ScopeCode'
45
+ ),
46
+ readAttribute('codeListValue'),
47
+ map(
48
+ (scopeCode): RecordKind =>
49
+ scopeCode === 'service' ? 'service' : 'dataset'
50
+ )
51
+ )(rootEl)
52
+ }
53
+
54
+ export function findDistribution() {
55
+ return findNestedElement('mdb:distributionInfo', 'mrd:MD_Distribution')
56
+ }
57
+
58
+ // from cit:CI_Organisation
59
+ export function extractOrganization(): ChainableFunction<
60
+ XmlElement,
61
+ Organization
62
+ > {
63
+ const getUrl = pipe(
64
+ findNestedElements(
65
+ 'cit:contactInfo',
66
+ 'cit:CI_Contact',
67
+ 'cit:onlineResource',
68
+ 'cit:CI_OnlineResource',
69
+ 'cit:linkage'
70
+ ),
71
+ getAtIndex(0),
72
+ extractUrl()
73
+ )
74
+ return pipe(
75
+ combine(
76
+ pipe(findChildElement('cit:name', false), extractCharacterString()),
77
+ getUrl
78
+ ),
79
+ map(([name, website]) => ({
80
+ name,
81
+ ...(website && { website }),
82
+ }))
83
+ )
84
+ }
85
+
86
+ // from cit:CI_Individual or cit:CI_Organisation
87
+ export function extractIndividual(
88
+ role: Role,
89
+ organization?: Organization,
90
+ orgContact?: Individual
91
+ ): ChainableFunction<XmlElement, Individual> {
92
+ const getPosition = pipe(
93
+ findChildElement('cit:positionName'),
94
+ extractCharacterString()
95
+ )
96
+ const getNameParts = pipe(
97
+ findChildElement('cit:name'),
98
+ extractCharacterString(),
99
+ map((fullName) => {
100
+ if (!fullName) return []
101
+ return fullNameToParts(fullName)
102
+ })
103
+ )
104
+ const getContact = findNestedElement('cit:contactInfo', 'cit:CI_Contact')
105
+ const getAddressRoot = pipe(
106
+ getContact,
107
+ findNestedElement('cit:address', 'cit:CI_Address')
108
+ )
109
+ const getAddress = pipe(
110
+ getAddressRoot,
111
+ combine(
112
+ pipe(
113
+ findChildElement('cit:deliveryPoint', false),
114
+ extractCharacterString()
115
+ ),
116
+ pipe(findChildElement('cit:city', false), extractCharacterString()),
117
+ pipe(findChildElement('cit:postalCode', false), extractCharacterString()),
118
+ pipe(findChildElement('cit:country', false), extractCharacterString())
119
+ ),
120
+ map((parts) => parts.filter((p) => !!p).join(', '))
121
+ )
122
+ const getPhone = pipe(
123
+ getContact,
124
+ findNestedElement('cit:phone', 'cit:CI_Telephone', 'cit:number'),
125
+ extractCharacterString()
126
+ )
127
+ const getEmail = pipe(
128
+ getAddressRoot,
129
+ findChildElement('cit:electronicMailAddress', false),
130
+ extractCharacterString()
131
+ )
132
+ const defaultOrg: Organization = {
133
+ name: 'Missing Organization',
134
+ }
135
+
136
+ let defaultIndividual: Partial<Individual> = {}
137
+ if (orgContact) {
138
+ defaultIndividual = {
139
+ email: orgContact.email,
140
+ ...(orgContact.address && { address: orgContact.address }),
141
+ ...(orgContact.phone && { phone: orgContact.phone }),
142
+ ...(orgContact.position && { position: orgContact.position }),
143
+ organization,
144
+ }
145
+ }
146
+
147
+ return pipe(
148
+ combine(getPosition, getNameParts, getEmail, getAddress, getPhone),
149
+ map(([position, [firstName, lastName], email, address, phone]) => ({
150
+ ...defaultIndividual,
151
+ email: email || defaultIndividual.email || 'missing@missing.com',
152
+ role,
153
+ organization: organization || defaultOrg,
154
+ ...(position && { position }),
155
+ ...(firstName && { firstName }),
156
+ ...(lastName && { lastName }),
157
+ ...(address && { address }),
158
+ ...(phone && { phone }),
159
+ }))
160
+ )
161
+ }
162
+
163
+ // from cit:CI_Organisation
164
+ export function extractOrganizationIndividuals(
165
+ role: Role
166
+ ): ChainableFunction<XmlElement, Array<Individual>> {
167
+ return pipe(
168
+ combine(
169
+ extractOrganization(),
170
+ extractIndividual(role),
171
+ findNestedElements('cit:individual', 'cit:CI_Individual')
172
+ ),
173
+ map(([org, orgContact, els]) =>
174
+ els.length
175
+ ? els.map((el) => extractIndividual(role, org, orgContact)(el))
176
+ : [
177
+ {
178
+ email: orgContact.email,
179
+ ...(orgContact.address && { address: orgContact.address }),
180
+ ...(orgContact.phone && { phone: orgContact.phone }),
181
+ ...(orgContact.position && { position: orgContact.position }),
182
+ organization: org,
183
+ role,
184
+ },
185
+ ]
186
+ )
187
+ )
188
+ }
189
+
190
+ // from cit:CI_Responsibility
191
+ export function extractIndividuals(): ChainableFunction<
192
+ XmlElement,
193
+ Array<Individual>
194
+ > {
195
+ const getRole = pipe(findChildElement('cit:role'), extractRole())
196
+ const getIndividuals = pipe(
197
+ combine(getRole, findNestedElements('cit:party', 'cit:CI_Individual')),
198
+ ([role, els]) => els.map((el) => extractIndividual(role)(el))
199
+ )
200
+ const getOrgIndividuals = pipe(
201
+ combine(getRole, findNestedElements('cit:party', 'cit:CI_Organisation')),
202
+ map(([role, els]) =>
203
+ els.map((el) => extractOrganizationIndividuals(role)(el))
204
+ ),
205
+ flattenArray()
206
+ )
207
+
208
+ return pipe(combine(getIndividuals, getOrgIndividuals), flattenArray())
209
+ }
210
+
211
+ export function readUniqueIdentifier(rootEl: XmlElement): string {
212
+ return pipe(
213
+ findNestedElement(
214
+ 'mdb:metadataIdentifier',
215
+ 'mcc:MD_Identifier',
216
+ 'mcc:code'
217
+ ),
218
+ extractCharacterString()
219
+ )(rootEl)
220
+ }
221
+
222
+ export function readOwnerOrganization(rootEl: XmlElement): Organization {
223
+ const contacts = readContacts(rootEl)
224
+ const pointOfContact = contacts.filter(
225
+ (c) => c.role === 'point_of_contact'
226
+ )[0]
227
+ return (pointOfContact || contacts[0]).organization
228
+ }
229
+
230
+ export function readContacts(rootEl: XmlElement): Individual[] {
231
+ return pipe(
232
+ findNestedElements('mdb:contact', 'cit:CI_Responsibility'),
233
+ mapArray(extractIndividuals()),
234
+ flattenArray()
235
+ )(rootEl)
236
+ }
237
+
238
+ export function readResourceContacts(rootEl: XmlElement): Individual[] {
239
+ return pipe(
240
+ combine(
241
+ pipe(
242
+ findIdentification(),
243
+ findNestedElements(
244
+ 'mri:citation',
245
+ 'cit:CI_Citation',
246
+ 'cit:citedResponsibleParty'
247
+ )
248
+ ),
249
+ pipe(
250
+ findIdentification(),
251
+ findChildrenElement('mri:pointOfContact', false)
252
+ ),
253
+ pipe(findDistribution(), findChildrenElement('mrd:distributorContact'))
254
+ ),
255
+ flattenArray(),
256
+ mapArray(findChildElement('cit:CI_Responsibility', false)),
257
+ mapArray(extractIndividuals()),
258
+ flattenArray()
259
+ )(rootEl)
260
+ }
261
+
262
+ export function readLandingPage(rootEl: XmlElement): URL {
263
+ return pipe(
264
+ findNestedElement(
265
+ 'mdb:metadataLinkage',
266
+ 'cit:CI_OnlineResource',
267
+ 'cit:linkage'
268
+ ),
269
+ extractUrl()
270
+ )(rootEl)
271
+ }
272
+
273
+ export function readLineage(rootEl: XmlElement): string {
274
+ return pipe(
275
+ findNestedElement('mdb:resourceLineage', 'mrl:LI_Lineage', 'mrl:statement'),
276
+ extractCharacterString()
277
+ )(rootEl)
278
+ }
279
+
280
+ function extractDateInfo(
281
+ type: 'creation' | 'revision' | 'publication'
282
+ ): ChainableFunction<XmlElement, Date> {
283
+ return pipe(
284
+ findChildrenElement('mdb:dateInfo', false),
285
+ filterArray(
286
+ (el) =>
287
+ pipe(
288
+ findChildElement('cit:CI_DateTypeCode'),
289
+ readAttribute('codeListValue')
290
+ )(el) === type
291
+ ),
292
+ getAtIndex(0),
293
+ findChildElement('cit:date'),
294
+ extractDateTime()
295
+ )
296
+ }
297
+
298
+ export function readRecordUpdated(rootEl: XmlElement): Date {
299
+ return extractDateInfo('revision')(rootEl)
300
+ }
301
+
302
+ export function readRecordCreated(rootEl: XmlElement): Date {
303
+ return extractDateInfo('creation')(rootEl)
304
+ }
305
+
306
+ export function readRecordPublished(rootEl: XmlElement): Date {
307
+ return extractDateInfo('publication')(rootEl)
308
+ }
309
+
310
+ const getMimeType = pipe(
311
+ findParent('mrd:MD_Distribution'),
312
+ findNestedElement(
313
+ 'mrd:distributionFormat',
314
+ 'mrd:MD_Format',
315
+ 'mrd:formatSpecificationCitation',
316
+ 'cit:CI_Citation',
317
+ 'cit:title'
318
+ ),
319
+ extractCharacterString(),
320
+ map(matchMimeType)
321
+ )
322
+
323
+ export function readDistributions(rootEl: XmlElement): DatasetDistribution[] {
324
+ return pipe(
325
+ findNestedElements('mrd:distributionInfo', 'mrd:MD_Distribution'),
326
+ mapArray(extractDatasetDistributions(getMimeType)),
327
+ flattenArray()
328
+ )(rootEl)
329
+ }