Мне удалось найти достаточно хорошее решение частично с помощью ответа, который кто-то опубликовал, но впоследствии удалил (мне довелось увидеть его и скопировать его код, прежде чем они удалили).
Ключом для меня было изучение функции attributes()
, которая извлекала нужную мне информацию из списков в более высоких частях иерархии. Мое решение ручное и не элегантное, но оно работает.
Ниже показано, что я сделал, чтобы получить данные до двух уровней. Я продолжаю вкладывать эти циклы while
и корректировать их логику до глубины 6 уровней. Предположим, что XML хранится в doc
.
xml_ls <- xml2::as_list(xml2::xml_find_all(doc, ".//Item"))
a_len <- length(attributes(xml_ls[[1]])$names)
a_name <- attributes(xml_ls[[1]])$Name
a_id <- attributes(xml_ls[[1]])$Id
a_item <- xml_ls[[1]]$Item
cat_level <- 1
cat_names <- a_name
cat_ids <- a_id
cat_items <- a_item
a_dir <- 1
#print(paste0("Top Level: ", a_name))
while (a_dir <= a_len){
b_len <- length(attributes(xml_ls[[1]][[a_dir]])$names)
b_name <- attributes(xml_ls[[1]][[a_dir]])$Name
b_id <- attributes(xml_ls[[1]][[a_dir]])$Id
b_item <- xml_ls[[1]][[a_dir]]$Item
#print(paste0("Level B: ", b_name))
cat_level <- c(cat_level, 2)
cat_names <- c(cat_names, b_name)
cat_ids <- c(cat_ids, b_id)
cat_items <- c(cat_items, b_item)
b_dir <- 1
while (b_dir <= b_len){
c_len <- length(attributes(xml_ls[[1]][[a_dir]][[b_dir]])$names)
c_name <- attributes(xml_ls[[1]][[a_dir]][[b_dir]])$Name
c_id <- attributes(xml_ls[[1]][[a_dir]][[b_dir]])$Id
c_item <- xml_ls[[1]][[a_dir]][[b_dir]]$Item
#print(paste0("Level C: ", c_name))
cat_level <- c(cat_level, 3)
cat_names <- c(cat_names, c_name)
cat_ids <- c(cat_ids, c_id)
cat_items <- c(cat_items, c_item)
Это создает списки, которые начинаются с "cat_". Затем я помещаю их в фрейм данных и манипулирую ими в нужной мне структуре:
df <- as_tibble(cbind(cat_level, cat_ids, cat_names)) %>%
mutate(cat_level = as.integer(cat_level))
df2 <- df %>%
mutate(a = if_else(cat_level == 1, cat_names, NA_character_),
b = if_else(cat_level == 2, cat_names, NA_character_),
c = if_else(cat_level == 3, cat_names, NA_character_),
d = if_else(cat_level == 4, cat_names, NA_character_),
e = if_else(cat_level == 5, cat_names, NA_character_),
f = if_else(cat_level == 6, cat_names, NA_character_)
) %>%
fill(c(a, b, c, d, e, f)) %>%
mutate(lvl1 = if_else(cat_level >= 1, a, NA_character_),
lvl2 = if_else(cat_level >= 2, b, NA_character_),
lvl3 = if_else(cat_level >= 3, c, NA_character_),
lvl4 = if_else(cat_level >= 4, d, NA_character_),
lvl5 = if_else(cat_level >= 5, e, NA_character_),
lvl6 = if_else(cat_level >= 6, f, NA_character_)) %>%
select(-a, -b, -c, -d, -e, -f)