L oop выбирается по узлам и выбирает подузлы на любом уровне в первом узле - PullRequest
1 голос
/ 28 апреля 2020

Я использую пакет xml2. Я хочу:

  1. Выбрать узлы с определенным тегом (в данном случае все envelope)
  2. L oop над этими узлами и выбрать узлы внутри независимо от вложенности (в в этом случае все value теги, найденные внутри card-entry тегов)
  3. Конкатенация текста с пробелом

Есть три конверта, поэтому я ожидаю, что смогу вернуть вектор из трех с полным текстом из тегов value, найденных внутри тегов card-entry. Я не могу сделать это 1027 *. Как я могу выполнить это 1028 *? Почему мои подходы ниже не работают?

MWE

library(xml2)

myxml <- read_xml('
<inside>
 <box>
   <card-entry>
     <card-id type="integer">605383</card-id>
     <value>get well</value>
   </card-entry>
 </box>
 <envelope>
     <card-entry>
       <card-id type="integer">605380</card-id>
       <value>coke</value>
     </card-entry>
     <card-entry>
       <card-id type="integer">610954</card-id>
       <value>pizza</value>
     </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>
     <subenvelope>
       <value>dont get me</value>
     </subenvelope>
     <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>
     <subenvelope>
       <card-entry>
         <card-id type="integer"></card-id>
         <value>jorb</value>
       </card-entry>
     </subenvelope>
     <card-entry>
       <card-id type="integer">605333</card-id>
       <value></value>
     </card-entry>    
 </envelope>
</inside>
'
)

Желаемый вывод

## [1] coke pizza surprise joke
## [2] charlie horse rug bug mario cart
## [3] trogdor jorb

Что я пробовал

children <- lapply(xml2::xml_find_all(myxml, '//envelope'), xml2::xml_children)

rm_na <- function(x) x[!is.na(x)]

lapply(children, function(x){

    paste(rm_na(unlist(xml2::xml_text(xml2::xml_child(x, '//card-entry//value')))), collapse = ' ')

})

## [[1]]
## [1] ""
## 
## [[2]]
## [1] ""
## 
## [[3]]
## [1] ""
## 
## There were 11 warnings (use warnings() to see them)


lapply(children, function(x){

    paste(rm_na(unlist(xml2::xml_text(xml2::xml_find_all(x, '//card-entry//value')))), collapse = ' ')

})

## [[1]]
## [1] "get well coke pizza surprise joke charlie horse rug bug mario cart trogdor jorb "
## 
## [[2]]
## [1] "get well coke pizza surprise joke charlie horse rug bug mario cart trogdor jorb "
## 
## [[3]]
## [1] "get well coke pizza surprise joke charlie horse rug bug mario cart trogdor jorb "

1 Ответ

1 голос
/ 28 апреля 2020

В вашем внутреннем селекторе вы хотите сделать его относительно текущего узла, так что вы хотите .// вместо //, который бы снова искал все дерево

sapply(xml_find_all(myxml,"//envelope"), function(x) 
  paste(xml_text(xml_find_all(x, ".//card-entry/value")), collapse=" ")
)

# [1] "coke pizza surprise joke"        
# [2] "charlie horse rug bug mario cart"
# [3] "trogdor jorb "  
...