xml2 - более эффективно получать информацию из родительских узлов
У меня есть XML выглядит так:
...
<node id=1>
<child>a</child>
<child>b</child>
<child>c</child>
</node>
<node id=2>
<child>d</child>
<child>e</child>
</node>
...
То, что я ищу, это data.frame со ссылкой на соответствующего родителя ребенка:
node_id child_text
1 a
1 b
1 c
2 d
2 e
Есть только 2 решения, которые я мог бы подумать об использовании xml2:
(a) создайте набор дочерних узлов, используя xml_find_all (...), а затем используйте цикл for для маневрирования через структуру xml для получения необходимой информации. Крайне неэффективно, очевидно.
(б) получить набор родительских узлов и набор дочерних узлов для каждого. Извлеките информацию из родительского набора и посчитайте, сколько детей у каждого из родителей. Затем использовал rep (information, no_of_children), чтобы заполнить столбец node_id сверху. Лучше, но все еще глупо.
Я предполагаю, что должен быть более эффективный способ? Я рад любому предложению, поскольку я использую эти подходы уже более месяца, имея дело с гигабитами - крайне неэффективных - структур данных в формате xml. Я также не ограничиваюсь использованием xml2 и могу также переключиться на другой язык программирования, если это значительно повысит производительность. Единственной важной частью является то, что я хотел бы загрузить данные непосредственно в базу данных оттуда.
1 ответ
Учитывая очень общий пример, который вы дали, я бы использовал rvest
вместе с purrr
:
x <- "<node id=1>
<child>a</child>
<child>b</child>
<child>c</child>
</node>
<node id=2>
<child>d</child>
<child>e</child>
</node>"
library(rvest)
library(purrr)
read_html(x) %>%
html_nodes('node') %>%
map_df(~{
.x %>%
html_nodes('child') %>%
html_text() -> child
data.frame(child = child, stringsAsFactors = FALSE)
}, .id = 'node')
#> node child
#> 1 1 a
#> 2 1 b
#> 3 1 c
#> 4 2 d
#> 5 2 e
И некоторые критерии для сравнения с вашими методами:
rbenchmark::benchmark(read_html(xml) %>%
html_nodes('node') %>%
map_df(~{
.x %>%
html_nodes('child') %>%
html_text() -> child
data.frame(child = child, stringsAsFactors = FALSE)
}, .id = 'node'), columns = c('replications', 'elapsed', 'user.self'))
#> replications elapsed user.self
#> 1 100 0.964 0.964