Непонятно, как именно вы хотели бы иметь структуру с несколькими уровнями вложенности и элементами с разными длинами, представленными в виде прямоугольного фрейма данных angular. Я предполагаю, что один из способов сделать это состоит в том, чтобы иметь одну строку с типом и содержимым каждого элемента, например:
library(xml2)
xml_doc <- readLines("md3.xml")
myXML <- xml2::read_xml(xml_doc)
elements <- unlist(xml2::as_list(myXML)$`document`);
data.frame(type = names(elements), contents = as.character(elements))
#> type contents
#> 1 heading.text level_1
#> 2 heading.text level_11
#> 3 list.item.paragraph.text ind1
#> 4 list.item.paragraph.text ind2
#> 5 heading.text level_12
#> 6 list.item.paragraph.text ind3
#> 7 heading.text level_2
#> 8 heading.text level_21
#> 9 heading.text level_211
#> 10 list.item.paragraph.text ind4
Существуют различные способы сохранить структуру вложенности, но все они немного произвольны. и искусственный, если у вас нет определенной цели c. Я с радостью помогу в достижении этой цели, если вы хотите расширить свой вопрос.
РЕДАКТИРОВАТЬ
С желаемым результатом, указанным в ОП, можно извлечь данные, которые нам нужны для поддержки вложенной структуры. Сначала нам нужно извлечь атрибут «level», а также любое содержимое из xml. Мы можем сделать это с помощью рекурсивной функции:
list_miner <- function(x)
{
if(!is.null(attr(x, "level"))) return(c(level = attr(x, "level"), x[[1]]))
if(class(x) == "list") return(lapply(x, list_miner))
else return(c( x))
}
Мы применяем функцию следующим образом:
xml_doc <- readLines("md3.xml")
myXML <- xml2::read_xml(xml_doc)
xlist <- xml2::as_list(myXML)
elements <- unlist(lapply(xlist, list_miner))
df <- data.frame(type = names(elements), contents = as.character(elements))
Теперь df
содержит всю необходимую нам информацию:
#> type contents
#> 1 document.heading.level 1
#> 2 document.heading level_1
#> 3 document.heading.level 2
#> 4 document.heading level_11
#> 5 document.list.item.paragraph.text ind1
#> 6 document.list.item.paragraph.text ind2
#> 7 document.heading.level 2
#> 8 document.heading level_12
#> 9 document.list.item.paragraph.text ind3
#> 10 document.heading.level 1
#> 11 document.heading level_2
#> 12 document.heading.level 2
#> 13 document.heading level_21
#> 14 document.heading.level 3
#> 15 document.heading level_211
#> 16 document.list.item.paragraph.text ind4
Преобразование его в правильный формат требует много трудностей, но вот как это может быть достигнуто:
df %>%
mutate(level1 = cumsum(1 * (type == "document.heading.level" & contents == "1"))) %>%
group_by(level1) %>%
mutate(level1text = contents[type == "document.heading"][1]) %>%
filter(level1 == 0 | seq_along(type) > 2) %>%
mutate(level2 = cumsum(1 * (type == "document.heading.level" & contents == "2"))) %>%
group_by(level1, level2) %>%
mutate(level2text = contents[type == "document.heading"][1]) %>%
filter(level2 == 0 | seq_along(type) > 2) %>%
mutate(level3 = cumsum(1 * (type == "document.heading.level" & contents == "3"))) %>%
group_by(level1, level2, level3) %>%
mutate(level3text = contents[type == "document.heading"][1]) %>%
filter(level3 == 0 | seq_along(type) > 2) %>%
ungroup() %>%
select(header_level_1 = level1text, header_level_2 = level2text,
header_level_3 = level3text, text = contents)
Что дает:
#> # A tibble: 4 x 4
#> header_level_1 header_level_2 header_level_3 text
#> <fct> <fct> <fct> <fct>
#> 1 level_1 level_11 <NA> ind1
#> 2 level_1 level_11 <NA> ind2
#> 3 level_1 level_12 <NA> ind3
#> 4 level_2 level_21 level_211 ind4