Cara mengurai XML ke bingkai data R.

103

Saya mencoba mengurai bingkai data XML ke R, tautan ini sangat membantu saya:

cara membuat bingkai data R dari file xml

Tapi tetap saja saya tidak bisa menemukan masalah saya:

Ini kode saya:

data <- xmlParse("http://forecast.weather.gov/MapClick.php?lat=29.803&lon=-82.411&FcstType=digitalDWML")
xmlToDataFrame(nodes=getNodeSet(data1,"//data"))[c("location","time-layout")]
step1 <- xmlToDataFrame(nodes=getNodeSet(data1,"//location/point"))[c("latitude","longitude")]
step2 <- xmlToDataFrame(nodes=getNodeSet(data1,"//time-layout/start-valid-time"))
step3 <- xmlToDataFrame(nodes=getNodeSet(data1,"//parameters/temperature"))[c("type="hourly"")]

Kerangka data yang ingin saya miliki adalah seperti ini:

latitude  longitude   start-valid-time   hourly_temperature
29.803     -82.411  2013-06-19T15:00:00-04:00    91
29.803     -82.411  2013-06-19T16:00:00-04:00    90

Saya terjebak di xmlToDataFrame(), Bantuan apa pun akan sangat dihargai, terima kasih.

Rosa
sumber

Jawaban:

103

Data dalam format XML jarang diatur sedemikian rupa sehingga memungkinkan xmlToDataFramefungsinya bekerja. Anda lebih baik mengekstrak semuanya dalam daftar dan kemudian mengikat daftar bersama-sama dalam bingkai data:

require(XML)
data <- xmlParse("http://forecast.weather.gov/MapClick.php?lat=29.803&lon=-82.411&FcstType=digitalDWML")

xml_data <- xmlToList(data)

Dalam kasus data contoh Anda, mendapatkan lokasi dan waktu mulai cukup mudah:

location <- as.list(xml_data[["data"]][["location"]][["point"]])

start_time <- unlist(xml_data[["data"]][["time-layout"]][
    names(xml_data[["data"]][["time-layout"]]) == "start-valid-time"])

Data suhu sedikit lebih rumit. Pertama, Anda perlu menuju ke node yang berisi daftar suhu. Kemudian Anda perlu mengekstrak kedua daftar, mencari di dalamnya, dan memilih salah satu yang memiliki "hourly" sebagai salah satu nilainya. Kemudian Anda hanya perlu memilih daftar itu tetapi hanya menyimpan nilai yang memiliki label "nilai":

temps <- xml_data[["data"]][["parameters"]]
temps <- temps[names(temps) == "temperature"]
temps <- temps[sapply(temps, function(x) any(unlist(x) == "hourly"))]
temps <- unlist(temps[[1]][sapply(temps, names) == "value"])

out <- data.frame(
  as.list(location),
  "start_valid_time" = start_time,
  "hourly_temperature" = temps)

head(out)
  latitude longitude          start_valid_time hourly_temperature
1    29.81    -82.42 2013-06-19T16:00:00-04:00                 91
2    29.81    -82.42 2013-06-19T17:00:00-04:00                 90
3    29.81    -82.42 2013-06-19T18:00:00-04:00                 89
4    29.81    -82.42 2013-06-19T19:00:00-04:00                 85
5    29.81    -82.42 2013-06-19T20:00:00-04:00                 83
6    29.81    -82.42 2013-06-19T21:00:00-04:00                 80
SchaunW
sumber
94

Gunakan xpath lebih langsung untuk performa dan kejelasan.

time_path <- "//start-valid-time"
temp_path <- "//temperature[@type='hourly']/value"

df <- data.frame(
    latitude=data[["number(//point/@latitude)"]],
    longitude=data[["number(//point/@longitude)"]],
    start_valid_time=sapply(data[time_path], xmlValue),
    hourly_temperature=as.integer(sapply(data[temp_path], as, "integer"))

menuju ke

> head(df, 2)
  latitude longitude          start_valid_time hourly_temperature
1    29.81    -82.42 2014-02-14T18:00:00-05:00                 60
2    29.81    -82.42 2014-02-14T19:00:00-05:00                 55
Martin Morgan
sumber
12
Ini seharusnya menjadi jawaban yang diterima. Ini lebih ringkas dan xpath memiliki kinerja yang jauh lebih baik daripada mengulang daftar.
SchaunW
40

Berikut solusi parsial menggunakan xml2. Memecah solusi menjadi bagian-bagian yang lebih kecil biasanya memudahkan untuk memastikan semuanya berbaris:

library(xml2)
data <- read_xml("http://forecast.weather.gov/MapClick.php?lat=29.803&lon=-82.411&FcstType=digitalDWML")

# Point locations
point <- data %>% xml_find_all("//point")
point %>% xml_attr("latitude") %>% as.numeric()
point %>% xml_attr("longitude") %>% as.numeric()

# Start time
data %>% 
  xml_find_all("//start-valid-time") %>% 
  xml_text()

# Temperature
data %>% 
  xml_find_all("//temperature[@type='hourly']/value") %>% 
  xml_text() %>% 
  as.integer()
hadley
sumber
8
Jawaban yang berguna. Jika ada orang lain yang tersandung, inilah tautan ke tutorial oleh Hadley tentang penggunaan xml2: blog.rstudio.com/2015/04/21/xml2
Richard Erickson
9

Anda dapat mencoba kode di bawah ini:

# Load the packages required to read XML files.
library("XML")
library("methods")

# Convert the input xml file to a data frame.
xmldataframe <- xmlToDataFrame("input.xml")
print(xmldataframe)
abhishek dandona
sumber