Получить xll xpaths в R с помощью xml2

В xml2 можно получить xpath данного узла, используя:

xml_path

Интересно, как быстрее всего извлечь все пути xpath из данного документа. Т.е. Я хочу найти конечные узлы, а затем выполнить итерацию вверх.

По сути, я пытаюсь добиться этого:

library(xml2)

#Read
doc <- read_xml("http://www.w3schools.com/xml/plant_catalog.xml")

#Define a funciton to extract all xpaths:
extract_all_paths<-function(x){
  if (xml_length(x)==0){
    final_vector<-xml_path(x)
  } else{
    final_vector<-list("vector")
    i<-1
    while (length(x)!=0){
      x<-do.call(c,lapply(x,xml_children))
      x_length<-sapply(x,xml_length)
      final_vector[[i]]<-x[x_length==0]
      x<-x[x_length!=0]
      i<-i+1
    }
    final_vector<-do.call(c,final_vector)
    final_vector<-sapply(final_vector,xml_path)
    final_vector
  }
  final_vector
}

#Function to extract everything for a given xpath:
function_extract_values<-function(x,y){
  paste(xml_text(xml_find_all(y,x)),collapse="&&&&")
}

format_file<-function(x){
  x<-xml_ns_strip(x)
  data_path<-data.table(x=xml_children(x))
  data_xpath<-data_path[,extract_all_paths(x),by=1:nrow(data_path)]
  data_xpath[,V1:=gsub("\\[(.*?)\\]","",data_xpath$V1)]
  data_xpath<-data_xpath[!duplicated(V1)]
  data_xpath[,V2:=list(list(x)),by=1:nrow(data_xpath)]
  data_xpath[,value:=function_extract_values(V1,V2[[1]]),by=1:nrow(data_xpath)]
  data_xpath[,V1:=gsub("\\/","_",V1)]
  data_names<-data_xpath$V1
  data_xpath[,V1:=NULL]
  data_xpath[,nrow:=NULL]
  data_xpath[,V2:=NULL]
  data_xpath<-transpose(data_xpath)
  setnames(data_xpath,data_names)
  data_xpath
}
data<-format_file(doc)

По сути, я хочу проанализировать файл .xml, а затем поместить его в виде строки в таблицу data.table. Мое текущее решение очень медленное, если у меня много файлов, может быть, кто-нибудь предложит более быстрое решение.


person Vitalijs    schedule 26.05.2017    source источник


Ответы (1)


Могут быть лучшие способы получить полный список xpath из документа, но вот одно решение. (Вероятно, есть и лучшие способы перебрать ваш XML-документ, чтобы получить то, что вы хотите, но вы запросили список всех xpath):

library(XML) #This may work in xml2 but i usually stick with XML

#read document into R and select root
myXML <- xmlTreeParse("myXML.xml", useInternal = TRUE)
top <- xmlRoot(myXML)
#convert XML to list of lists
temp <- xmlToList(top)

#use names of recusive apply to get list of recusive steps through XML
temp <- unique(names(rapply(test, summary, how="unlist")))
#remove the last item created by summary function
temp <- unique(sub("\\.[^.]*$", "", temp))
#remove attributes
temp <- unique(sub("..attrs", "", temp))
#sub . for / to create xpath
temp <- sub("\\.","/", temp)
#add / to start the xpath at the docuemnt root
XPaths <- paste0("/", temp)
person Ian Wesley    schedule 26.05.2017
comment
это не будет работать с некоторыми странными пространствами имен, есть идеи, как с ними обращаться? - person Vitalijs; 26.05.2017
comment
Вы могли бы удалить странные пространства имен, если бы вы могли опубликовать пример, я могу помочь ... Однако что вы пытаетесь сделать? Вероятно, есть способ сделать это лучше. - person Ian Wesley; 30.05.2017
comment
@ Дело в том, что у меня есть .xml, где я не знаю структуры, я хочу извлечь все возможные поля! - person Vitalijs; 30.05.2017
comment
Без знания структуры вашего XML-файла невозможно извлечь все поля в значимые таблицы, потому что вы не знаете, как поля соотносятся друг с другом. Не существует единого стандартного способа форматирования XML. Например, все теги под заданным тегом являются частью одной и той же таблицы, или все они являются отдельными таблицами, а значения являются атрибутами, или являются первичным ключом для таблицы, хранящейся вместе с ее тегом или в теге над ним. Невозможно узнать, не глядя на свои данные. Функции XML::xmlElementSummary & xm2::xml_structure могут помочь вам изучить ваши данные. - person Ian Wesley; 31.05.2017
comment
Я расширил свой пример, возможно, вы можете предложить более эффективное решение - person Vitalijs; 31.05.2017
comment
Все ли ваши данные просты, как в примере, или у вас есть более сложный XML, содержащий данные из нескольких таблиц или на нескольких уровнях? Если это будет сложнее, и вы сделаете это так, как проиллюстрировали, вы потеряете способность связывать свои данные вместе, это нормально? - person Ian Wesley; 31.05.2017
comment
это как я проиллюстрировал, единственное, что мне нужно объединить некоторые наблюдения с &&&& - person Vitalijs; 31.05.2017
comment
если это так, как показано на рисунке, все, что вам нужно сделать, это: df <- XML::xmlToDataFrame("plant_catalog.xml"), за которым следует myList <- lapply(df, function(x) paste0(x, collapse="&&&")) - person Ian Wesley; 31.05.2017
comment
К сожалению, он по-прежнему не сворачивает мой документ на нужном уровне, если я усложняю .xml, тогда как мое решение делает для произвольно сложного набора данных - person Vitalijs; 31.05.2017
comment
Позвольте нам продолжить это обсуждение в чате. - person Ian Wesley; 31.05.2017