Объедините значения в огромные XML-файлы
Мне нужно найти и объединить информацию в некоторых огромных XML-файлах (doc <- xmlInternalTreeParse (file.name, useInternalNodes = TRUE, trim = TRUE) приводит к тому, что мой компьютер на 16 ГБ начинает загружаться на диск перед завершением), и следовал хорошим инструкциям на http://www.omegahat.org/RSXML/Overview.html.
Добавляя к примеру оттуда, это более или менее похоже на мой файл:
<?xml version="1.0" ?>
<TABLE>
<SCHOOL>
<NAME> School1 </NAME>
<GRADES>
<STUDENT> Fred </STUDENT>
<TEST1> 66 </TEST1>
<TEST2> 80 </TEST2>
<FINAL> 70 </FINAL>
</GRADES>
<TEAMS>
<SOCCER> SoccerTeam1 </SOCCER>
<HOCKEY> HockeyTeam1 </HOCKEY>
</TEAMS>
</SCHOOL>
<SCHOOL>
<NAME> School2 </NAME>
<GRADES>
<STUDENT> Wilma </STUDENT>
<TEST1> 97 </TEST1>
<TEST2> 91 </TEST2>
<FINAL> 98 </FINAL>
</GRADES>
<TEAMS>
<SOCCER> SoccerTeam2 </SOCCER>
</TEAMS>
</SCHOOL>
</TABLE>
Мне нужно составить список учащихся по школам с хоккейной командой и названиями команд. Требуемый вывод из примера должен быть "Fred", "HockeyTeam1", "School1". Реальный пример - тысячи "школ", "хоккейных команд" и "игроков".
Как я могу использовать xmlEventParse для анализа файлов для извлечения информации? Я пытался извлечь все текстовые поля из файлов, но после нескольких часов ожидания все еще не было вывода. Примечание: реальные файлы более вложены, чем это, поэтому не нужно переходить на фиксированные уровни, чтобы найти информацию.
2 ответа
Мы будем использовать пакет XML
library(XML)
и создайте замыкание, которое содержит функцию для обработки узла 'SCHOOL', а также две вспомогательные функции для получения результатов по завершении. Функция SCHOOL вызывается на каждом узле SCHOOL. Если он находит хоккейную команду, он использует /SCHOOL/NAME/text() в качестве "ключа", а /SCHOOL/TEAMS/HOCKEY/text() и //STUDENT/text() (или /SCHOOL/GRADES/ СТУДЕНТ / текст ()) в качестве значений. Сообщение печатается для каждых 100 (по умолчанию) школ с хоккейными командами, так что есть некоторые признаки прогресса. Функция get используется после факта для получения результата.
teams <- function(progress=1000) {
res <- new.env(parent=emptyenv()) # for results
it <- 0L # iterator -- nodes visited
list(SCHOOL=function(elt) {
## handle 'SCHOOL' nodes
if (getNodeSet(elt, "not(/SCHOOL/TEAMS/HOCKEY)"))
## early exit -- no hockey team
return(NULL)
it <<- it + 1L
if (it %% progress == 0L)
message(it)
school <- getNodeSet(elt, "string(/SCHOOL/NAME/text())") # 'key'
res[[school]] <-
list(team=getNodeSet(elt,
"normalize-space(/SCHOOL/TEAMS/HOCKEY/text())"),
students= xpathSApply(elt, "//STUDENT", xmlValue))
}, getres = function() {
## retrieve the 'res' environment when done
res
}, get=function() {
## retrieve 'res' environment as data.frame
school <- ls(res)
team <- unlist(eapply(res, "[[", "team"), use.names=FALSE)
student <- eapply(res, "[[", "students")
len <- sapply(student, length)
data.frame(school=rep(school, len), team=rep(team, len),
student=unlist(student, use.names=FALSE))
})
}
Мы используем функцию как
branches <- teams()
xmlEventParse("event.xml", handlers=NULL, branches=branches)
branches$get()
Я думаю, что вы можете работать с нормальным фреймом данных. Итак, для этого:
f=xmlParse('file.xml')
df=xmlToDataFrame(f)
тогда у вас есть фрейм данных, установите некоторые условия для фильтрации объектов. или вы хотите работать с деревом xml, атрибутами и значением?
r=xmlRoot(f)
Вызовите r или любую ветвь наподобие r[[1]][[1]]. <NAME> School1 </NAME>