XML-документ как дерево от корня до листьев в r

Я пытаюсь представить древовидную структуру XML-документа в виде списка путей или списка объединенных имен узлов. Например:

<node id="A">
   <node id = "AA">
       <node id = "AAA"></node>
   </node>
   <node id = "AB">
   </node>
   <node id = "AC">
   </node>
</node>

Следует преобразовать в это:

//A/AA/AAA 
//A/AB
//A/AC

Или это:

A, AA, AAA 
A, AB
A, AC

Я нашел примеры на других языках:

Получить список всех корневых пути к концам в дереве DOM

Но я не уверен, как перебирать узлы в R. Я использую пакет xml2.

Кто-нибудь решил эту проблему? Прошу друга.


person why.knot    schedule 07.07.2016    source источник
comment
Ну, может быть xml %>% read_xml() %>% xml_find_all('//*') %>% xml_path(), но это не совсем то, что вы ожидаете.   -  person alistaire    schedule 07.07.2016
comment
Это работает! Я только что разместил как решение ниже. Спасибо!   -  person why.knot    schedule 09.07.2016


Ответы (2)


Здесь работает решение, предложенное @alistaire в комментариях выше.

Просто не забудьте убрать пространство имен.

library( dplyr )
library( xml2 )

dat <- read_xml( "https://s3.amazonaws.com/irs-form-990/201541349349307794_public.xml" )
dat %>% xml_find_all( '//*') %>% xml_path()
#  [1] "/*"                            "/*/*[1]"                      
#  [3] "/*/*[1]/*[1]"                  "/*/*[1]/*[2]"                 
#  [5] "/*/*[1]/*[3]"                  "/*/*[1]/*[3]/*[1]" 


xml_ns_strip( dat )
dat %>% xml_find_all( '//*') %>% xml_path()
#  [1] "/Return"                                                                                               
#  [2] "/Return/ReturnHeader"                                                                                  
#  [3] "/Return/ReturnHeader/ReturnTs"  
person why.knot    schedule 09.07.2016

Вот решение с использованием пакета «xml2». Я написал эту функцию, чтобы найти клапан на каждом узле, но в вашем случае мы просто ищем атрибут «id» для каждого узла.
Цель состоит в том, чтобы найти все узлы верхнего уровня без дочерних элементов и извлечь их значения, затем перейти к узлам с дочерними элементами. Затем повторяйте эту функцию рекурсивно, пока не будут найдены и обработаны наибольшие узлы-потомки.

library(xml2)
file<-read_xml('<node id="A">
   <node id = "AA">
               <node id = "AAA"></node>
               </node>
               <node id = "AB">
               </node>
               <node id = "AC">
               </node>
               </node>')

findchildren<-function(nodes, df){
  numchild<-sapply(nodes, function(x){length(xml_children(x))})
  #extract out the attribute, value and parents
  xmlattr<-xml_attr(nodes[numchild==0], "id")
  #xmlvalue<-xml_text(nodes[numchild==0])  #value of node
  xmlpath<-sapply(nodes[numchild==0], function(x) {toString(rev(xml_attr(xml_parents(x), "id")))})

  #dftemp<-data.frame(xmlattr, xmlvalue, xmlpath)
  dftemp<-data.frame(xmlpath, xmlattr)

  #merge results back to master df
  df<-rbind(df, dftemp)
  print(dim(df))  #Print statement for status
  #End of recursion
  if (sum(numchild)>0){
    findchildren(xml_children(nodes[numchild>0]), df) }
  else{ return(df)}
}

df<-data.frame()
df<-findchildren(xml_children(file), df) 
apply(df, 1, toString)

Эта функция выводит кадр данных из 2 столбцов. Первый столбец — это путь xml к узлу во втором столбце. Я использовал команду apply, чтобы объединить эти 2 столбца вместе для вашего окончательного решения. Порядок в конечном списке основан не на исходной конструкции документа, а на перечислении родительских, затем дочерних, внуков узлов.... Эта функция повторно вызывает rbind не самый эффективный метод, но приемлемый, если количество дочерних уровней не слишком велик.

Надеюсь, что это работает для вас.

person Dave2e    schedule 08.07.2016
comment
Спасибо! Это было очень полезно для понимания того, как применять функции к наборам узлов и выбирать на основе атрибутов. Умная рекурсия, а также. См. выше простое решение. - person why.knot; 09.07.2016