xml - 抓住 subsubchild 并在 child 内折叠,即使元素文本缺失
xml - grab subsubchild and collapse within child even when element text missing
我有一个嵌套的 xml 数据集,如下所示,我正在尝试使用 xml2 和 进行解析tidyverse 包。共有三个 child 个信封。我想在每个 <envelope>
标签中获取 <card-id>
和 <value>
subsub child 标签的所有文本,并用易于识别的分隔符折叠它们,例如 ;;;
或从中列出 data.frames 个。
MWE:这是数据:
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>
我想我可以在 child 上使用 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()
)
})
不太漂亮,但是您可以通过首先将每个信封的所有子项放入单独的列表元素,然后循环获取每个 card-id 的文本来获取 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
对于 NA 而不是 "",您可以在每个 xml_text
之后添加 %>% ifelse(. == "", NA, .)
我有一个嵌套的 xml 数据集,如下所示,我正在尝试使用 xml2 和 进行解析tidyverse 包。共有三个 child 个信封。我想在每个 <envelope>
标签中获取 <card-id>
和 <value>
subsub child 标签的所有文本,并用易于识别的分隔符折叠它们,例如 ;;;
或从中列出 data.frames 个。
MWE:这是数据:
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>
我想我可以在 child 上使用 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()
)
})
不太漂亮,但是您可以通过首先将每个信封的所有子项放入单独的列表元素,然后循环获取每个 card-id 的文本来获取 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
对于 NA 而不是 "",您可以在每个 xml_text
%>% ifelse(. == "", NA, .)