r - 如何将嵌套的 XML 导入 R 数据框
问题描述
我希望将以下 XML 文档导入数据框: http: //opensource.adobe.com/Spry/data/donuts.xml
应该创建 3 个数据框:
- 项目 - (字段 = ID 类型名称 PPU)
- 击球手 - (字段 = BatterID、BatterName、ItemID - Items 数据框的键)
- Toppings - (Fields = ToppingID, ToppingName, ItemID - Items 数据框的键)
(数据不需要是 3NF - 即每个击球手可以针对它列出的每个项目重复)
使用 XML2 包,到目前为止,我已使用以下代码导入 XML 并将其转换为嵌套列表:
library(xml2)
xmlobj <- read_xml("http://opensource.adobe.com/Spry/data/donuts.xml")
ls1 <- as_list(xmlobj) #Converts XML to a nested list
我现在希望将列表解析/展平为如上所述的 3 个数据帧。
如何最好地实现这一目标?是通过一系列循环(lapply/map),将对象传递到向量然后加载数据框吗?或者我应该完全避免使用 XML2 / Lists 并使用 XML 包并使用 XPath 类型语法来实现这一点?
我尝试了以下方法,可以提取单个项目的 Item 属性和元素,但是当我尝试 lapply 函数时它崩溃了:
#Function for pulling out item attributes from list
ItemDF <- function(myItem){
#Gather Item data into DF including attributes
itemFrame <- data_frame(
id = attr(myItem$item,'id'),
type = attr(myItem$item,'type'),
name = unlist(myItem$item$name),
ppu = unlist(myItem$item$ppu)
)
return(itemFrame)
}
#Single instance
df1 <- ItemDF(ls1$items[1])
df1
#Lapply across all items throws an error
lapply(ls1$items,ItemDF)
(注意这个数据集是一个概念证明,所以我正在寻找一种方法,然后我可以适应我期望使用的其他 XML 文件)。
解决方案
library(xml2)
library( tidyverse )
xmlobj <- read_xml("http://opensource.adobe.com/Spry/data/donuts.xml")
df_items <- data.frame(
id = xml_find_all( xmlobj, ".//item" ) %>% xml_attr( "id" ),
type = xml_find_all( xmlobj, ".//item" ) %>% xml_attr( "type" ),
name = xml_find_all( xmlobj, ".//item/name" ) %>% xml_text(),
ppu = xml_find_all( xmlobj, ".//item/ppu" ) %>% xml_text(),
stringsAsFactors = FALSE )
# id type name ppu
# 1 0001 donut Cake 0.55
# 2 0002 donut Raised 0.55
# 3 0003 donut Buttermilk 0.55
# 4 0004 bar Bar 0.75
# 5 0005 twist Twist 0.65
# 6 0006 filled Filled 0.75
df_batters <- xml_find_all( xmlobj, ".//item" ) %>%
map_df(~{
set_names(
xml_find_all(.x, ".//batters/batter") %>% xml_attr( "id" ),
xml_find_all(.x, ".//batters/batter") %>% xml_text()
) %>%
as.list() %>%
flatten_df() %>%
mutate(itemID = xml_attr(.x, "id" ) )
}) %>%
type_convert() %>%
gather( batter, batterID, -itemID, na.rm = TRUE) %>%
select( batterID, batter, itemID )
# # A tibble: 10 x 3
# batterID batter itemID
# * <int> <chr> <chr>
# 1 1001 Regular 0001
# 2 1001 Regular 0002
# 3 1001 Regular 0003
# 4 1001 Regular 0004
# 5 1001 Regular 0005
# 6 1001 Regular 0006
# 7 1002 Chocolate 0001
# 8 1002 Chocolate 0003
# 9 1003 Blueberry 0001
# 10 1003 Devil's Food 0001
df_toppings <- xml_find_all( xmlobj, ".//item" ) %>%
map_df(~{
set_names(
xml_find_all(.x, ".//topping") %>% xml_attr( "id" ),
xml_find_all(.x, ".//topping") %>% xml_text()
) %>%
as.list() %>%
flatten_df() %>%
mutate(itemID = xml_attr(.x, "id" ) )
}) %>%
type_convert() %>%
gather( topping, toppingID, -itemID, na.rm = TRUE) %>%
select( toppingID, topping, itemID )
# # A tibble: 20 x 3
# toppingID topping itemID
# * <int> <chr> <chr>
# 1 5001 None 0001
# 2 5001 None 0002
# 3 5002 Glazed 0001
# 4 5002 Glazed 0002
# 5 5002 Glazed 0005
# 6 5002 Glazed 0006
# 7 5005 Sugar 0001
# 8 5005 Sugar 0002
# 9 5005 Sugar 0005
# 10 5007 Powdered Sugar 0001
# 11 5007 Powdered Sugar 0006
# 12 5006 Chocolate with Sprinkles 0001
# 13 5003 Chocolate 0001
# 14 5003 Chocolate 0002
# 15 5003 Chocolate 0004
# 16 5003 Chocolate 0006
# 17 5004 Maple 0001
# 18 5004 Maple 0002
# 19 5004 Maple 0004
# 20 5004 Maple 0006
推荐阅读
- javascript - 无法设置未定义错误的属性“onaddtrack”
- python - 使用 pivot_table 时,NaN 列 pandas 变成空行
- angular - Angular:仅显示组件并隐藏页眉和页脚
- javascript - jquery animate 在第一次点击时不起作用
- next.js - 在下一个 js 中使用 getStaticProps 未在 props 中获取 API 响应数据
- google-api - HttpError 400 在 users().messages().list 使用服务帐户调用 Gmail API 期间先决条件检查失败
- mysql - MySQL:删除同一行时发生死锁
- c++ - POCO C++ MongoDB:将 std::string 转换为 MongoDB::Document
- android - 如何在片段内使用 RecyclerView 实现无限列表
- machine-learning - sklearn 交叉有效/交叉预测