Skip to content

Commit 80d13af

Browse files
committed
Adding code to handle Container items
1 parent 09ee7b8 commit 80d13af

File tree

3 files changed

+209
-35
lines changed

3 files changed

+209
-35
lines changed

lib/Toolbar.js

+10
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,15 @@ class Toolbar {
866866
template_name = Object.keys(schema.classes).find(
867867
(e) => schema.classes[e].is_a === 'dh_interface'
868868
);
869+
// We need to get template name from first Container attributes'
870+
// class's range.
871+
if (!template_name && 'Container' in schema.classes) {
872+
Object.entries(schema.classes.Container.attributes).forEach(([class_name, class_obj]) => {
873+
if (class_obj.range in schema.classes) {
874+
template_name = class_obj.range;
875+
}
876+
});
877+
}
869878
} catch (err) {
870879
console.error(err);
871880
return null;
@@ -1020,6 +1029,7 @@ class Toolbar {
10201029
}
10211030

10221031
setupJumpToModal(dh) {
1032+
10231033
const columnCoordinates = dh.getColumnCoordinates();
10241034

10251035
// Initialize and reset the jump-to input field

script/oca_to_linkml.py

+182-34
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@
3636
# Detecting OCA data types via regular expression Numeric, Text,
3737
#
3838
# Numeric:
39-
# integer or decimal number, may begin with + or - /^[-+]?\d*\.?\d+$/gm
40-
# integer /^-?[0-9]+$/gm
39+
# integer or decimal number, may begin with + or - /^[-+]?\d*\.?\d+$
40+
# integer /^-?[0-9]+$
4141
#
4242
# Textual:
43-
# Entries of any length with only capital letters ^[A-Z]*$
4443
# Capital or lower case letters only, at least 1 character, and 50 characters max ^[A-Za-z]{1,50}$
4544
# Capital or lower case letters only, 50 characters max ^[A-Za-z]{0,50}$
4645
# Short text, 50 characters max ^.{0,50}$
@@ -55,31 +54,6 @@
5554
# Latitude in formats S30°15'45.678" or N12°30.999" ^[NS]-?(?:[0-8]?\d|90)°(?:\d+(?:\.\d+)?)(?:'(\d+(?:\.\d+)?)")?$
5655
# Longitude in formats E30°15'45.678" or W90°00.000" ^[WE]-?(?:[0-8]?\d|90)°(?:\d+(?:\.\d+)?)(?:'(\d+(?:\.\d+)?)")?$
5756
#
58-
# Date
59-
#
60-
# ISO: YYYY-MM-DD: year month day ^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
61-
# ISO: YYYYMMDD: year month day ^(\d{4})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[0-1])$
62-
# ISO: YYYY-MM: year month ^(\d{4})-(0[1-9]|1[0-2])$
63-
# ISO: YYYY-Www: year week (e.g. W01) ^(?:\d{4})-W(0[1-9]|[1-4][0-9]|5[0-3])$
64-
# ISO: YYYYWww: year week (e.g. W01) ^(?:\d{4})W(0[1-9]|[1-4][0-9]|5[0-3])$
65-
# ISO: YYYY-DDD: Ordinal date (day number from the year) ^(?:\d{4})-(00[1-9]|0[1-9][0-9]|[1-2][0-9]{2}|3[0-5][0-9]|36[0-6])$
66-
# ISO: YYYYDDD: Ordinal date (day number from the year) ^(?:\d{4})(00[1-9]|0[1-9][0-9]|[1-2][0-9]{2}|3[0-5][0-9]|36[0-6])$
67-
# ISO: YYYY: year ^(\d{4})$
68-
# ISO: MM: month ^(0[1-9]|1[0-2])$
69-
# ISO: DD: day ^(0[1-9]|[1-2][0-9]|3[01])$
70-
# ISO: YYYY-MM-DDTHH:MM:SSZ: Date and Time Combined (UTC) ^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):([0-5]\d):([0-5]\d)Z$
71-
# ISO: YYYY-MM-DDTHH:MM:SS±hh:mm: Date and Time Combined (with Timezone Offset) ^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):([0-5]\d):([0-5]\\d)([+-][01]\\d:[0-5]\d)$
72-
# ISO: PnYnMnDTnHnMnS :durations e.g. P3Y6M4DT12H30M5S ^P(?!$)((\d+Y)|(\d+.\d+Y)$)?((\d+M)|(\d+.\d+M)$)?((\d+W)|(\d+.\d+W)$)?((\d+D)|(\d+.\d+D)$)?(T(?=\d)((\d+H)|(\d+.\d+H)$)?((\d+M)|(\d+.\d+M)$)?(\d+(.\d+S)?)?)?$
73-
# ISO: HH:MM: hour, minutes in 24 hour notation ^([01]\d|2[0-3]):([0-5]\d)$
74-
# ISO: HH:MM:SS: hour, minutes, seconds in 24 hour notation ^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$
75-
# DD/MM/YYYY: day, month, year ^(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{4}$
76-
# DD/MM/YY: day, month, year ^(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{2}$
77-
# MM/DD/YYYY: month, day, year ^(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{4}$
78-
# DDMMYYYY: day, month, year ^(0[1-9]|[12]\d|3[01])(0[1-9]|1[0-2])\d{4}$
79-
# MMDDYYYY: month, day, year ^(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{4}$
80-
# YYYYMMDD: year, month, day ^(\d{4})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[0-1])$
81-
# HH:MM:SS: hour, minutes, seconds 12 hour notation AM/PM ^(0?[1-9]|1[0-2]):[0-5][0-9]:[0-5][0-9] ?[APMapm]{2}$
82-
# H:MM or HH:MM: hour, minutes AM/PM ^(0?[1-9]|1[0-2]):[0-5][0-9] ?[APMapm]{2}$
8357

8458

8559
import json
@@ -107,9 +81,9 @@
10781
prefixes:
10882
linkml: https://w3id.org/linkml/
10983
classes:
110-
dh_interface:
111-
name: dh_interface
112-
description: A DataHarmonizer interface
84+
Container:
85+
name: "Container"
86+
tree_root: True
11387
slots: {}
11488
enums: {}
11589
types:
@@ -121,6 +95,165 @@
12195
#x9 (tab), #xA (linefeed), and #xD (carriage return)."
12296
base: str
12397
uri: xsd:token
98+
99+
AllCaps:
100+
name: AllCaps
101+
description: Entries of any length with only capital letters
102+
typeof: string
103+
base: str
104+
pattern: ^[A-Z]*$
105+
AlphaText1-50:
106+
name: AlphaText1-50
107+
description: Capital or lower case letters only, at least 1 character, and 50 characters max
108+
pattern: ^[A-Za-z]{1,50}$
109+
AlphaText0-50:
110+
name: AlphaText0-50
111+
description: Capital or lower case letters only, 50 characters max
112+
pattern: ^[A-Za-z]{0,50}$
113+
FreeText0-50:
114+
name: FreeText0-50
115+
description: Short text, 50 characters max
116+
pattern: ^.{0,50}$
117+
FreeText0-250:
118+
name: FreeText0-250
119+
description: Short text, 250 characters max
120+
pattern: ^.{0,250}$
121+
FreeText0-800:
122+
name: FreeText0-800
123+
description: Long text, 800 characters max
124+
pattern: ^.{0,800}$
125+
FreeText0-4000:
126+
name: FreeText0-4000
127+
description: Long text, 4000 characters max
128+
pattern: ^.{0,4000}$
129+
CanadianPostalCode:
130+
name: CanadianPostalCode
131+
description: Canadian postal codes (A1A 1A1)
132+
pattern: ^[A-Z][0-9][A-Z]\s[0-9][A-Z][0-9]$
133+
ZipCode:
134+
name: ZipCode
135+
description: Zip code
136+
pattern: ^\d{5,6}(?:[-\s]\d{4})?$
137+
EmailAddress:
138+
name: EmailAddress
139+
description: Email address
140+
pattern: ^[a-zA-Z0-9_\.\+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-\.]+
141+
URL:
142+
name: URL
143+
description: Secure (https) URL
144+
pattern: ^https?\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}$
145+
PhoneNumber:
146+
name: PhoneNumber
147+
description: Phone number with international and area code component.
148+
pattern: ^\+?\(?\d{2,4}\)?[\d\s-]{3,}$
149+
Latitude:
150+
name: Latitude
151+
description: Latitude in formats S30°15'45.678" or N12°30.999"
152+
pattern: ^[NS]-?(?:[0-8]?\d|90)°(?:\d+(?:\.\d+)?)(?:'(\d+(?:\.\d+)?)")?$
153+
Longitude:
154+
name: Longitude
155+
description: Longitude in formats E30°15'45.678" or W90°00.000"
156+
pattern: ^[WE]-?(?:[0-8]?\d|90)°(?:\d+(?:\.\d+)?)(?:'(\d+(?:\.\d+)?)")?$
157+
158+
ISO_YYYY-MM-DD:
159+
name: ISO_YYYY-MM-DD
160+
description: year month day
161+
pattern: ^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
162+
typeof: string
163+
base: str
164+
uri: xsd:token
165+
ISO_YYYYMMDD:
166+
name: ISO_YYYYMMDD
167+
pattern: ^(\d{4})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[0-1])$
168+
typeof: string
169+
base: str
170+
uri: xsd:token
171+
ISO_YYYY-MM:
172+
name: ISO_YYYY-MM
173+
description: year month
174+
pattern: ^(\d{4})-(0[1-9]|1[0-2])$
175+
ISO_YYYY-Www:
176+
name: ISO_YYYY-Www
177+
description: year week (e.g. W01)
178+
pattern: ^(?:\d{4})-W(0[1-9]|[1-4][0-9]|5[0-3])$
179+
ISO_YYYYWww:
180+
name: ISO_YYYYWww
181+
description: year week (e.g. W01)
182+
pattern: ^(?:\d{4})W(0[1-9]|[1-4][0-9]|5[0-3])$
183+
ISO_YYYY-DDD:
184+
name: ISO_YYYY-DDD
185+
description: Ordinal date (day number from the year)
186+
pattern: ^(?:\d{4})-(00[1-9]|0[1-9][0-9]|[1-2][0-9]{2}|3[0-5][0-9]|36[0-6])$
187+
ISO_YYYYDDD:
188+
name: ISO_YYYYDDD
189+
description: Ordinal date (day number from the year)
190+
pattern: ^(?:\d{4})(00[1-9]|0[1-9][0-9]|[1-2][0-9]{2}|3[0-5][0-9]|36[0-6])$
191+
ISO_YYYY:
192+
name: ISO_YYYY
193+
description: year
194+
pattern: ^(\d{4})$
195+
ISO_MM:
196+
name: ISO_MM
197+
description: month
198+
pattern: ^(0[1-9]|1[0-2])$
199+
ISO_DD:
200+
name: ISO_DD
201+
description: day
202+
pattern: ^(0[1-9]|[1-2][0-9]|3[01])$
203+
"ISO_YYYY-MM-DDTHH:MM:SSZ":
204+
name: ISO_YYYY-MM-DDTHH:MM:SSZ
205+
description: Date and Time Combined (UTC)
206+
pattern: ^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):([0-5]\d):([0-5]\d)Z$
207+
"ISO_YYYY-MM-DDTHH:MM:SS±hh:mm":
208+
name: ISO_YYYY-MM-DDTHH:MM:SS±hh:mm
209+
description: Date and Time Combined (with Timezone Offset)
210+
pattern: ^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):([0-5]\d):([0-5]\\d)([+-][01]\\d:[0-5]\d)$
211+
ISO_PnYnMnDTnHnMnS:
212+
name: ISO_PnYnMnDTnHnMnS
213+
description: durations e.g. P3Y6M4DT12H30M5S
214+
pattern: ^P(?!$)((\d+Y)|(\d+.\d+Y)$)?((\d+M)|(\d+.\d+M)$)?((\d+W)|(\d+.\d+W)$)?((\d+D)|(\d+.\d+D)$)?(T(?=\d)((\d+H)|(\d+.\d+H)$)?((\d+M)|(\d+.\d+M)$)?(\d+(.\d+S)?)?)?$
215+
"ISO_HH:MM":
216+
name: ISO_HH:MM
217+
description: hour, minutes in 24 hour notation
218+
pattern: ^([01]\d|2[0-3]):([0-5]\d)$
219+
"ISO_HH:MM:SS":
220+
name: ISO_HH:MM:SS
221+
description: hour, minutes, seconds in 24 hour notation
222+
pattern: ^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$
223+
DD/MM/YYYY:
224+
name: DD/MM/YYYY
225+
description: day, month, year
226+
pattern: ^(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{4}$
227+
DD/MM/YY:
228+
name: DD/MM/YY
229+
description: day, month, year
230+
pattern: ^(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{2}$
231+
MM/DD/YYYY:
232+
name: MM/DD/YYYY
233+
description: month, day, year
234+
pattern: ^(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{4}$
235+
DDMMYYYY:
236+
name: DDMMYYYY
237+
description: day, month, year
238+
pattern: ^(0[1-9]|[12]\d|3[01])(0[1-9]|1[0-2])\d{4}$
239+
MMDDYYYY:
240+
name: MMDDYYYY
241+
description: month, day, year
242+
pattern: ^(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{4}$
243+
YYYYMMDD:
244+
name: YYYYMMDD
245+
description: year, month, day
246+
pattern: ^(\d{4})(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[0-1])$
247+
"HH:MM:SS":
248+
name: HH:MM:SS
249+
description: hour, minutes, seconds 12 hour notation AM/PM
250+
pattern: ^(0?[1-9]|1[0-2]):[0-5][0-9]:[0-5][0-9] ?[APMapm]{2}$
251+
"H:MM or HH:MM":
252+
name: H:MM or HH:MM
253+
description: hour, minutes AM/PM
254+
pattern: ^(0?[1-9]|1[0-2]):[0-5][0-9] ?[APMapm]{2}$
255+
256+
124257
settings:
125258
Title_Case: '((?<=\b)[^a-z\W]\w*?|[\W])+'
126259
UPPER_CASE: '[A-Z\W\d_]*'
@@ -252,8 +385,17 @@ def writeSchemaCore():
252385
'name': SCHEMA["name"],
253386
'title': SCHEMA["title"] or SCHEMA["name"],
254387
'description': SCHEMA["description"],
255-
'is_a': 'dh_interface'
388+
# 'is_a': 'dh_interface'
256389
}
390+
391+
# Set up Container class to hold given schema class's data
392+
SCHEMA["classes"]['Container']['attributes'] = {
393+
'name': SCHEMA["name"] + 'Data',
394+
'multivalued': True,
395+
'range': SCHEMA["name"],
396+
'inlined_as_list': True
397+
}
398+
257399
# ISSUE: Each class may have (meta) title and description fields translated
258400
# but we don't have a SCHEMA_CLASSES table to handle translations in
259401
# tabular_to_schema.py, so can't communicate them.
@@ -272,6 +414,7 @@ def writeSlots():
272414

273415
for slot_name in oca_attributes:
274416
slot = slots[slot_name];
417+
slot['slot_group'] = "General"; #Default; ideally not needed.
275418
slot['class_name'] = SCHEMA["name"];
276419
slot['name'] = slot_name;
277420
slot['title'] = oca_labels[slot_name];
@@ -283,7 +426,8 @@ def writeSlots():
283426
if slot_name in oca_entry_codes:
284427
slots[slot_name]['range_2'] = slot_name;
285428

286-
# post-process range field:
429+
# Conversion of range field from OCA to LinkML data types.
430+
# See https://github.com/ClimateSmartAgCollab/JSON-Form-Generator/blob/main/src/JsonFormGenerator.js
287431
match slot['range']: # case sensitive?
288432
case "Text":
289433
slot['range'] = "WhitespaceMinimizedString" # or "string"
@@ -296,12 +440,16 @@ def writeSlots():
296440
slot['range'] = "integer";
297441
else:
298442
slot['range'] = "decimal";
443+
case "DateTime":
444+
case "Boolean":
445+
299446

447+
case ""
300448
# Need access to original oca language parameter, e.g. "eng"
301449
if len(locale_mapping) > 1:
302450
for locale in list(locale_mapping)[1:]:
303451
oca_locale = locale_mapping[locale];
304-
#slot['slot_group_'+locale]
452+
slot['slot_group_'+locale] = "Generic";
305453
slot['title_'+locale] = getLookup("label", oca_locale, slot_name)
306454
slot['description_'+locale] = getLookup("information", oca_locale, slot_name)
307455
#slot['comments_'+locale]

script/tabular_to_schema.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,11 @@ def write_schema(schema):
494494
for name, class_obj in schema_view.all_classes().items():
495495
# Note classDef["@type"]: "ClassDefinition" is only in json output
496496
# Presence of "slots" in class indicates field hierarchy
497+
# Error trap is_a reference to non-existent class
498+
if "is_a" in class_obj and class_obj['is_a'] and (not class_obj['is_a'] in schema['classes']):
499+
print("Error: Class ", name, "has an is_a reference to a Class [", class_obj['is_a'], " ]which isn't defined. This reference needs to be removed.");
500+
sys.exit(0);
501+
497502
if schema_view.class_slots(name):
498503
new_obj = schema_view.induced_class(name);
499504
schema_view.add_class(new_obj);
@@ -571,10 +576,21 @@ def write_menu(menu_path, schema_folder, schema_view):
571576

572577
# Now cycle through each template:
573578
for class_name, class_obj in class_menu.items():
579+
display = 'is_a' in class_obj and class_obj['is_a'] == 'dh_interface';
580+
# Old DataHarmonizer <=1.9.1 included class_name in menu via "display"
581+
# if it had an "is_a" attribute = "dh_interface".
582+
# DH > 1.9.1 also displays if class is mentined in a "Container" class
583+
# attribute [Class name 2].range = class_name
584+
if display == False and 'Container' in schema_view.schema.classes:
585+
container = schema_view.get_class('Container');
586+
for container_name, container_obj in container['attributes'].items():
587+
if container_obj['range'] == class_name:
588+
display = True;
589+
break;
574590

575591
menu[schema_name]['templates'][class_name] = {
576592
"name": class_name,
577-
"display": 'is_a' in class_obj and class_obj['is_a'] == 'dh_interface'
593+
"display": display
578594
};
579595

580596
annotations = schema_view.annotation_dict(class_name);

0 commit comments

Comments
 (0)