R语言中XML对象列表提取重复值错误及xml2包节点提取问题
嘿,我正好处理过Scopus API的XML数据,来帮你解决这个问题!
首先,咱们得先理清问题的核心:你手里的列表是分批次返回的结果(每个元素含25条记录),首先要把这个嵌套列表拆成单条记录为元素的扁平列表,再处理缺失值提取就不会有重复问题了。
步骤1:扁平化你的XML列表
你需要把每个批次里的25条记录单独拆出来,合并成一个大的、每条记录对应一个元素的列表。假设你的原始列表叫scopus_responses,每个元素是从API返回的XML对象:
library(xml2) library(purrr) # 用flatten来简化嵌套结构 # 从每个批次中提取单条记录节点,合并成扁平列表 all_records <- flatten(lapply(scopus_responses, function(batch) { # 这里的xpath要对应Scopus返回的记录节点,一般是<abstracts-retrieval-response> xml_find_all(batch, "//abstracts-retrieval-response") }))
步骤2:处理XML命名空间(关键!)
Scopus的XML带一堆命名空间(比如dc:、prism:、ce:),直接写xpath会找不到节点,要么提前去掉命名空间,要么在xpath里指定命名空间。我个人习惯去掉,更省心:
# 给每条记录去掉命名空间,这样xpath不用写前缀 all_records <- map(all_records, xml_ns_strip)
步骤3:自定义提取函数,处理缺失值返回NULL
直接用xml_find_first找不到节点时会返回xml_missing类型,咱们写个小函数把它转成NULL,同时提取节点文本:
safe_extract <- function(record, xpath) { # 用相对路径(.//)确保只在当前记录内部搜索,避免跨记录提取导致重复 node <- xml_find_first(record, paste0(".//", xpath)) # 判断是否找到节点,没找到就返回NULL if (inherits(node, "xml_missing") || xml_length(node) == 0) { return(NULL) } # 提取节点文本,如果你需要节点本身就去掉xml_text xml_text(node) }
步骤4:批量提取字段
现在就可以用lapply或者purrr::map批量提取你需要的字段了,比如标题、DOI、作者:
# 提取标题 record_titles <- lapply(all_records, safe_extract, xpath = "title") # 提取DOI record_dois <- lapply(all_records, safe_extract, xpath = "doi") # 提取第一作者(如果需要多个作者可以用xml_find_all配合xml_text) first_authors <- lapply(all_records, safe_extract, xpath = "author/indexed-name")
为什么之前会出现重复值?
大概率是两个原因:
- 没有扁平化列表:直接对含25条记录的批次XML用
xml_find_first,它会返回整个批次里的第一个匹配节点,然后你循环每个批次时,这个值会被重复25次; - xpath用了全局路径:比如写
//title而不是.//title,这样会在整个XML文档(整个批次)里搜索所有标题,而不是当前记录内部,导致提取到的内容重复混乱。
这样处理后,不仅能得到每条记录对应一个元素的结果,缺失值也会正确返回NULL,不会有重复问题啦!
内容的提问来源于stack exchange,提问作者bcarothers
相关产品推荐
相关产品推荐

