Я пытаюсь извлечь значения из институциональных файлов XML с помощью R. Вот пример такого файла:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<missions xmlns="http://sensored">
<mission missiontype="2" year="2012" platform="4135" missionnumber="1" missiontypename="Referanseflåten-Hav" callsignal="LJBD" platformname="Nybo">
<startdate>30/01/2012</startdate>
<stopdate>28/11/2012</stopdate>
<purpose></purpose>
<fishstation serialno="86001">
<nation>58</nation>
<platform>4135</platform>
<station>1</station>
<startdate>30/01/2012</startdate>
<starttime>18:56:00</starttime>
<stopdate>30/01/2012</stopdate>
<stoptime>23:19:00</stoptime>
<latitudestart>65.13833</latitudestart>
<longitudestart>-11.04833</longitudestart>
<system>2</system>
<area>59</area>
<location>07</location>
<bottomdepthstart>653.0</bottomdepthstart>
<bottomdepthstop>653.0</bottomdepthstop>
<fishingdepthmax>85.0</fishingdepthmax>
<fishingdepthmin>40.0</fishingdepthmin>
<gear>3711</gear>
<gearcount>1</gearcount>
<gearcondition>4</gearcondition>
<trawlquality>7</trawlquality>
<dataquality>2</dataquality>
<catchsample species="161722.G03" samplenumber="1" noname="sild'G03" aphia="126417">
<sampletype>20</sampletype>
<conservation>1</conservation>
<producttype>1</producttype>
<weight>10.0</weight>
<count>46</count>
<sampleproducttype>1</sampleproducttype>
<lengthmeasurement>E</lengthmeasurement>
<lengthsampleweight>0.863</lengthsampleweight>
<lengthsamplecount>4</lengthsamplecount>
<specimensamplecount>4</specimensamplecount>
<individual specimenno="1">
<producttype>1</producttype>
<weight>0.222</weight>
<lengthunit>2</lengthunit>
<length>0.28</length>
</individual>
<individual specimenno="2">
<producttype>1</producttype>
<weight>0.127</weight>
<lengthunit>2</lengthunit>
<length>0.245</length>
</individual>
<individual specimenno="3">
<producttype>1</producttype>
<weight>0.172</weight>
<lengthunit>2</lengthunit>
<length>0.26</length>
</individual>
<individual specimenno="4">
<producttype>1</producttype>
<weight>0.342</weight>
<lengthunit>2</lengthunit>
<length>0.325</length>
</individual>
</catchsample>
</fishstation>
</mission>
</missions>
Мне удалось разобрать файл без проблем. Хотя имена отображаются в проанализированном списке правильно, я не могу правильно их проанализировать для использования языка XPath:
library(xml2)
library(xmltools)
doc <- xml2::read_xml("test.xml")
doc %>% xmltools::xml_view_trees()
#└── mission
# ├── startdate
# ├── stopdate
# ├── purpose
# └── fishstation
# ├── nation
# ├── platform
# ├── station
# ├── startdate
# ├── starttime
# ├── stopdate
# ├── stoptime
# ├── latitudestart
# ├── longitudestart
# ├── system
# ├── area
# ├── location
# ├── bottomdepthstart
# ├── bottomdepthstop
# ├── fishingdepthmax
# ├── fishingdepthmin
# ├── gear
# ├── gearcount
# ├── gearcondition
# ├── trawlquality
# ├── dataquality
# └── catchsample
# ├── sampletype
# ├── conservation
# ├── producttype
# ├── weight
# ├── count
# ├── sampleproducttype
# ├── lengthmeasurement
# ├── lengthsampleweight
# ├── lengthsamplecount
# ├── specimensamplecount
# ├── individual
# ├── producttype
# ├── weight
# ├── lengthunit
# └── length
# ├── individual
# ├── producttype
# ├── weight
# ├── lengthunit
# └── length
# ├── individual
# ├── producttype
# ├── weight
# ├── lengthunit
# └── length
# └── individual
# ├── producttype
# ├── weight
# ├── lengthunit
# └── length
doc %>% xmltools::xml_get_paths()
#[[1]]
# [1] "/*/*" "/*/*/*" "/*/*/*" "/*/*/*" #"/*/*/*" "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" #"/*/*/*/*" "/*/*/*/*"
# [12] "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" #"/*/*/*/*" "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" #"/*/*/*/*" "/*/*/*/*"
# [23] "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" "/*/*/*/*" #"/*/*/*/*" "/*/*/*/*/*" "/*/*/*/*/*" "/*/*/*/*/*" "/*/*/*/*/*" #"/*/*/*/*/*" "/*/*/*/*/*"
# [34] "/*/*/*/*/*" "/*/*/*/*/*" "/*/*/*/*/*" "/*/*/*/*/*" #"/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*/*" #"/*/*/*/*/*" "/*/*/*/*/*/*"
# [45] "/*/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*" #"/*/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*/*" "/*/*/*/*/*" #"/*/*/*/*/*/*" "/*/*/*/*/*/*"
# [56] "/*/*/*/*/*/*" "/*/*/*/*/*/*"
Скажем, я хочу извлечь долготу и широту для каждого fishstation
вместе с кодом вида и индивидуальным весом для каждой выбранной рыбы. Я могу сделать это, используя не очень эффективный способ памяти, преобразовав XML-документ в список и используя стандартный код R:
library(XML)
doc <- xmlInternalTreeParse("test.xml")
getNodeSet(doc, "//fishstation") # Does not work
getNodeSet(doc, "/*/*/*/*") # Works
tmp <- xmlToList(doc)[[1]]
tmp <- tmp[names(tmp) == "fishstation"]
lapply(tmp, function(k) {
sp <- k$catchsample$.attrs
inds <- k$catchsample
inds <- inds[names(inds) == "individual"]
data.frame(lon = k$longitudestart, lat = k$latitudestart,
sp = unname(sp[names(sp) == "species"]),
weight = unname(sapply(inds, function(j) j$weight)))
})
# $fishstation
# lon lat sp weight
# 1 -11.04833 65.13833 161722.G03 0.222
# 2 -11.04833 65.13833 161722.G03 0.127
# 3 -11.04833 65.13833 161722.G03 0.172
# 4 -11.04833 65.13833 161722.G03 0.342
Однако было бы чрезвычайно удобно использовать для этого язык XPath, поскольку такой подход значительно ускорит процесс (мои файлы могут иметь размер несколько гигабайт). Пока мне не удалось настроить процедуру извлечения таким образом, чтобы использование языка XPath работало для этих файлов. Я прекрасно понимаю, что это могло произойти из-за фундаментальной ошибки пользователя. Раньше я не работал с XML-файлами.
1) Как мне прочитать файл примера в R, чтобы имена узлов сохранились?
2) Как мне извлечь значения из приведенного выше примера более эффективным с точки зрения памяти способом?