xml - захватить sububchild и свернуть внутри дочернего элемента, даже если текст элемента отсутствует
У меня есть вложенный набор данных xml, подобный приведенному ниже, который я пытаюсь проанализировать с пакетами w / xml2 и tidyverse. Есть три детских конверта. Я хочу взять весь текст для <card-id>
а также <value>
дочерние теги subub в каждом <envelope>
пометить и свернуть их с легко идентифицируемым разделителем, как ;;;
или составьте список data.frames из них.
МВЭ: Вот данные:
library(xml2)
library(tidyverse)
myxml <- read_xml('
<inside>
<envelope>
<card-entry>
<card-id type="integer">605380</card-id>
<value>coke</value>
<random></random>
</card-entry>
<card-entry>
<card-id type="integer">610954</card-id>
<value>pizza</value>
<random>false</random>
</card-entry>
<card-entry>
<card-id type="integer">605381</card-id>
<value>surprise</value>
</card-entry>
<card-entry>
<card-id type="integer">610958</card-id>
<value>joke</value>
<random>true</random>
</card-entry>
</envelope>
<envelope>
<card-entry>
<card-id type="integer">605381</card-id>
<value>charlie horse</value>
</card-entry>
<card-entry>
<card-id type="integer">605380</card-id>
<value>rug bug</value>
</card-entry>
<card-entry>
<card-id type="integer">610954</card-id>
<value>mario cart</value>
</card-entry>
</envelope>
<envelope>
<card-entry>
<card-id type="integer">605377</card-id>
<value>trogdor</value>
</card-entry>
<card-entry>
<card-id type="integer"></card-id>
<value>jorb</value>
</card-entry>
<card-entry>
<card-id type="integer">605333</card-id>
<value></value>
</card-entry>
</envelope>
</inside>
'
)
Желаемый результат:
c(
"605380;;;coke;;;610954;;;pizza;;;605381;;;surprise;;;610958;;;joke",
"605381;;;charlie horse;;;605380;;;rug bug;;;610954;;;mario cart",
"605377;;;trogdor;;;;;;jorb;;;605333;;;"
)
Или так же хорошо (может быть, лучше) вложенный список, как это:
[[1]]
card_id value
1 605380 coke
2 610954 pizza
3 605381 surprise
4 610958 joke
[[2]]
card_id value
1 605381 charlie horse
2 605380 rug bug
3 610954 mario cart
[[3]]
card_id value
1 605377 trogdor
2 <NA> jorb
3 605333 <NA>
Я думал, что мог бы использовать as_list
на ребенка, а затем использовать xml_find_all
создать список data.frames но as_list
+ lapply
не атакует только один envelope
но делает их все с каждым проходом (было бы неплохо узнать, что мне не хватает в этой функции тоже).
Что я пробовал
myxml %>%
xml_find_all('//envelope') %>%
as_list() %>%
lapply(function(x){
data_frame(
card_id = x %>% xml_find_all('//card-id') %>% xml_text(),
value = x %>% xml_find_all('//value') %>% xml_text()
)
})
1 ответ
Не совсем красиво, но вы можете получить список data.frames, сначала собрав все дочерние элементы каждого конверта в отдельные элементы списка, а затем пройдя по циклу, чтобы получить текст от каждого идентификатора карты и узла значения.
myxml %>%
xml_find_all('//envelope') %>%
lapply(xml_children) %>%
lapply(function(x) data.frame(
card_id = xml_child(x, 'card-id') %>% xml_text,
value = xml_child(x, 'value') %>% xml_text
)
)
#[[1]]
# card_id value
#1 605380 coke
#2 610954 pizza
#3 605381 surprise
#4 610958 joke
#
#[[2]]
# card_id value
#1 605381 charlie horse
#2 605380 rug bug
#3 610954 mario cart
#
#[[3]]
# card_id value
#1 605377 trogdor
#2 jorb
#3 605333
Для НС вместо "" можно добавить %>% ifelse(. == "", NA, .)
после каждого xml_text