使用tidyr的unnest_wider展开同名列表时数据丢失问题求助
解决OAI-DC XML转Tibble时重复字段覆盖问题
问题根源
R原生列表不允许重复命名元素,xmlconvert::xml_to_list默认会用后出现的重复XML节点覆盖先出现的,导致后续unnest_wider展开时所有同名列值都被最后一个节点值覆盖——修改names_repair参数无法解决,因为重复节点的信息在列表转换阶段就已经丢失了。
解决方案
有两种可行路径,根据你的偏好选择:
路径1:改用xml2手动提取节点(更可控)
直接用xml2包解析XML,保留重复节点为向量,避免信息丢失:
library(xml2) library(tidyverse) # 读取XML文档 doc <- read_xml("doc.xml") # 定位所有<record>节点(适配多记录场景) records <- xml_find_all(doc, ".//record") # 定义单条记录提取函数 extract_record <- function(record) { # 提取header信息 header <- list( identifier = xml_find_first(record, ".//identifier") %>% xml_text(), datestamp = xml_find_first(record, ".//datestamp") %>% xml_text() ) # 提取metadata,重复的subject.other转为向量 metadata <- list( publisher = xml_find_first(record, ".//publisher") %>% xml_text(), subject_other = xml_find_all(record, ".//subject.other") %>% xml_text(), title = xml_find_first(record, ".//title") %>% xml_text() ) list(header = header, metadata = metadata) } # 批量处理所有记录 doc_list <- map(records, extract_record) # 转换为tibble并展开为带序号的列 final_df <- tibble(data = doc_list) %>% unnest_wider(data) %>% unnest_wider(header) %>% unnest_wider(metadata, names_sep = "_") %>% # 将subject_other向量转为带序号的列 mutate(subject_other = map(subject_other, ~set_names(., paste0("subject_other_", seq_along(.))))) %>% unnest_wider(subject_other)
路径2:调整xmlconvert参数保留重复节点
如果坚持用xmlconvert,修改duplicate_node_handling参数,让重复节点转为列表而非覆盖:
library(xmlconvert) library(tidyverse) library(xml2) # 转换XML为列表,保留重复节点为子列表 doc_list <- xml_to_list(read_xml("doc.xml"), duplicate_node_handling = "as_list") # 转换为tibble并展开 final_df <- tibble::enframe(doc_list) %>% unnest_wider(value, names_repair = "universal") %>% unnest_wider(metadata, names_sep = "_") %>% # 将重复的subject.other子列表转为带序号的列 mutate(metadata_subject.other = map(metadata_subject.other, ~set_names(., paste0("subject_other_", seq_along(.))))) %>% unnest_wider(metadata_subject.other)
效果验证
两种方法都会生成subject_other_1到subject_other_N的列,每个列对应XML里的一个<subject.other>节点值,不会出现覆盖问题,同时适配多记录XML的批量处理。
内容的提问来源于stack exchange,提问作者PierreGeorge
相关产品推荐
相关产品推荐

