@@ -133,54 +133,55 @@ parse_works <- function(json_data, orcid_id) {
133133
134134 records <- lapply(groups , function (group ) {
135135 summaries <- safe_extract(group , " work-summary" )
136- if (is.null(summaries )) {
136+ if (is.null(summaries ) || length( summaries ) == 0 ) {
137137 return (NULL )
138138 }
139139
140- lapply(summaries , function (summary ) {
141- if (is.null(summary )) {
142- return (NULL )
143- }
140+ # Only take the first work-summary to avoid duplicates
141+ # Multiple work-summaries in a group represent the same work from different sources
142+ summary <- summaries [[1 ]]
144143
145- # Extract title
146- title <- safe_extract(summary , " title" , " title" , " value" )
147-
148- # Extract DOI from external IDs
149- doi <- NA_character_
150- ext_ids <- safe_extract(summary , " external-ids" , " external-id" )
151- if (! is.null(ext_ids ) && is.list(ext_ids )) {
152- for (ext_id in ext_ids ) {
153- if (
154- ! is.null(ext_id ) &&
155- identical(safe_extract(ext_id , " external-id-type" ), " doi" )
156- ) {
157- doi <- safe_extract(ext_id , " external-id-value" )
158- break
159- }
144+ if (is.null(summary )) {
145+ return (NULL )
146+ }
147+
148+ # Extract title
149+ title <- safe_extract(summary , " title" , " title" , " value" )
150+
151+ # Extract DOI from external IDs
152+ doi <- NA_character_
153+ ext_ids <- safe_extract(summary , " external-ids" , " external-id" )
154+ if (! is.null(ext_ids ) && is.list(ext_ids )) {
155+ for (ext_id in ext_ids ) {
156+ if (
157+ ! is.null(ext_id ) &&
158+ identical(safe_extract(ext_id , " external-id-type" ), " doi" )
159+ ) {
160+ doi <- safe_extract(ext_id , " external-id-value" )
161+ break
160162 }
161163 }
164+ }
162165
163- # Extract URL
164- url <- safe_extract(summary , " url" , " value" )
166+ # Extract URL
167+ url <- safe_extract(summary , " url" , " value" )
165168
166- list (
167- orcid = orcid_id ,
168- put_code = as.character(safe_extract(summary , " put-code" )),
169- title = title ,
170- type = safe_extract(summary , " type" ),
171- publication_date = orcid_date_to_iso(safe_extract(
172- summary ,
173- " publication-date"
174- )),
175- journal = safe_extract(summary , " journal-title" , " value" ),
176- doi = doi ,
177- url = url
178- )
179- })
169+ list (
170+ orcid = orcid_id ,
171+ put_code = as.character(safe_extract(summary , " put-code" )),
172+ title = title ,
173+ type = safe_extract(summary , " type" ),
174+ publication_date = orcid_date_to_iso(safe_extract(
175+ summary ,
176+ " publication-date"
177+ )),
178+ journal = safe_extract(summary , " journal-title" , " value" ),
179+ doi = doi ,
180+ url = url
181+ )
180182 })
181183
182- records_flat <- unlist(records , recursive = FALSE )
183- records_flat <- records_flat [! vapply(records_flat , is.null , logical (1 ))]
184+ records_flat <- records [! vapply(records , is.null , logical (1 ))]
184185
185186 if (length(records_flat ) == 0 ) {
186187 return (data.table :: data.table(
@@ -364,7 +365,12 @@ parse_peer_reviews <- function(json_data, orcid_id) {
364365parse_affiliations <- function (json_data , orcid_id ) {
365366 groups <- safe_extract(json_data , " affiliation-group" )
366367
367- if (is.null(groups ) || length(groups ) == 0 ) {
368+ # Check if groups is NA (not just NULL)
369+ if (
370+ is.null(groups ) ||
371+ length(groups ) == 0 ||
372+ (length(groups ) == 1 && is.na(groups ))
373+ ) {
368374 return (data.table :: data.table(
369375 orcid = character (0 ),
370376 put_code = character (0 ),
@@ -381,26 +387,26 @@ parse_affiliations <- function(json_data, orcid_id) {
381387
382388 records <- lapply(groups , function (group ) {
383389 summaries <- safe_extract(group , " summaries" )
384- if (is.null(summaries )) {
390+ if (is.null(summaries ) || (length( summaries ) == 1 && is.na( summaries )) ) {
385391 return (NULL )
386392 }
387393
388394 lapply(summaries , function (item ) {
389395 # Try different summary types
390396 summary <- safe_extract(item , " distinction-summary" )
391- if (is.null(summary )) {
397+ if (is.null(summary ) || (length( summary ) == 1 && is.na( summary )) ) {
392398 summary <- safe_extract(item , " invited-position-summary" )
393399 }
394- if (is.null(summary )) {
400+ if (is.null(summary ) || (length( summary ) == 1 && is.na( summary )) ) {
395401 summary <- safe_extract(item , " membership-summary" )
396402 }
397- if (is.null(summary )) {
403+ if (is.null(summary ) || (length( summary ) == 1 && is.na( summary )) ) {
398404 summary <- safe_extract(item , " qualification-summary" )
399405 }
400- if (is.null(summary )) {
406+ if (is.null(summary ) || (length( summary ) == 1 && is.na( summary )) ) {
401407 summary <- safe_extract(item , " service-summary" )
402408 }
403- if (is.null(summary )) {
409+ if (is.null(summary ) || (length( summary ) == 1 && is.na( summary )) ) {
404410 return (NULL )
405411 }
406412
@@ -932,8 +938,13 @@ parse_search_results <- function(json_data) {
932938 num_found <- 0L
933939 }
934940
935- # Extract results array
936- results <- safe_extract(json_data , " result" )
941+ # Extract results array - use expanded-result for v3.0 API
942+ results <- safe_extract(json_data , " expanded-result" )
943+
944+ # Fall back to "result" if expanded-result doesn't exist (older API versions)
945+ if (is.null(results ) || (length(results ) == 1 && is.na(results ))) {
946+ results <- safe_extract(json_data , " result" )
947+ }
937948
938949 # Handle empty results (safe_extract returns NA for null)
939950 if (
@@ -954,36 +965,55 @@ parse_search_results <- function(json_data) {
954965
955966 # Parse each result
956967 parsed <- lapply(results , function (item ) {
957- # Extract ORCID identifier
968+ # Extract ORCID identifier - handle both formats
958969 orcid_path <- safe_extract(item , " orcid-identifier" , " path" )
959- orcid_id <- if (! is.null(orcid_path )) orcid_path else NA_character_
960-
961- # Extract given names
962- given_names <- safe_extract(item , " given-names" )
963- if (is.null(given_names )) {
964- given_names <- NA_character_
970+ if (is.null(orcid_path ) || is.na(orcid_path )) {
971+ # Try direct orcid-id field (expanded-search format)
972+ orcid_path <- item [[" orcid-id" ]]
965973 }
966-
967- # Extract family name
968- family_name <- safe_extract(item , " family-names" )
969- if (is.null(family_name )) {
970- family_name <- NA_character_
971- }
972-
973- # Extract credit name
974- credit_names <- safe_extract(item , " credit-name" )
975- credit_name <- if (! is.null(credit_names ) && length(credit_names ) > 0 ) {
976- credit_names [[1 ]]
974+ orcid_id <- if (! is.null(orcid_path ) && ! is.na(orcid_path )) {
975+ orcid_path
977976 } else {
978977 NA_character_
979978 }
980979
980+ # Helper function to safely extract and convert to character
981+ extract_name_field <- function (field_name ) {
982+ val <- item [[field_name ]]
983+ if (is.null(val )) {
984+ return (NA_character_ )
985+ }
986+ if (length(val ) == 0 ) {
987+ return (NA_character_ )
988+ }
989+ if (is.list(val )) {
990+ # If it's a list, try to get the first non-null element
991+ for (i in seq_along(val )) {
992+ if (! is.null(val [[i ]]) && length(val [[i ]]) > 0 ) {
993+ return (as.character(val [[i ]]))
994+ }
995+ }
996+ return (NA_character_ )
997+ }
998+ # Direct value
999+ return (as.character(val ))
1000+ }
1001+
1002+ # Extract name fields
1003+ given_names <- extract_name_field(" given-names" )
1004+ family_name <- extract_name_field(" family-names" )
1005+ credit_name <- extract_name_field(" credit-name" )
1006+
9811007 # Extract other names
982- other_names_data <- safe_extract(item , " other-names" )
1008+ other_names_val <- item [[" other-names" ]]
1009+ if (is.null(other_names_val )) {
1010+ # Try alternate field name
1011+ other_names_val <- item [[" other-name" ]]
1012+ }
9831013 other_names <- if (
984- ! is.null(other_names_data ) && length(other_names_data ) > 0
1014+ ! is.null(other_names_val ) && length(other_names_val ) > 0
9851015 ) {
986- other_names_data
1016+ if (is.list( other_names_val )) other_names_val else list ( other_names_val )
9871017 } else {
9881018 list (character (0 ))
9891019 }
0 commit comments