Cách phân tích cú pháp XML thành khung dữ liệu R


102

Tôi đã cố gắng phân tích cú pháp XML thành khung dữ liệu R, liên kết này đã giúp tôi rất nhiều:

cách tạo khung dữ liệu R từ tệp xml

Nhưng tôi vẫn không thể tìm ra vấn đề của mình:

Đây là mã của tôi:

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"")]

Khung dữ liệu tôi muốn có như sau:

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

Tôi bị mắc kẹt ở xmlToDataFrame(), Mọi sự giúp đỡ sẽ được đánh giá rất cao, cảm ơn.

Câu trả lời:


103

Dữ liệu ở định dạng XML hiếm khi được tổ chức theo cách cho phép xmlToDataFramehàm hoạt động. Tốt hơn hết bạn nên trích xuất mọi thứ trong danh sách và sau đó liên kết các danh sách với nhau trong một khung dữ liệu:

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

xml_data <- xmlToList(data)

Trong trường hợp dữ liệu mẫu của bạn, việc lấy vị trí và thời gian bắt đầu khá đơn giản:

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"])

Dữ liệu nhiệt độ phức tạp hơn một chút. Trước tiên, bạn cần đến nút có chứa danh sách nhiệt độ. Sau đó, bạn cần trích xuất cả hai danh sách, xem xét từng danh sách và chọn danh sách có "giờ" làm một trong các giá trị của nó. Sau đó, bạn chỉ cần chọn danh sách đó nhưng chỉ giữ lại các giá trị có nhãn "giá trị":

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

93

Sử dụng xpath trực tiếp hơn để có cả hiệu suất và độ rõ ràng.

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"))

dẫn tới

> 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

12
Đây thực sự phải là câu trả lời được chấp nhận. Nó ngắn gọn hơn và xpath có hiệu suất tốt hơn nhiều so với việc lặp qua các danh sách.
SchaunW

39

Đây là một giải pháp từng phần bằng cách sử dụng xml2. Chia dung dịch thành nhiều phần nhỏ hơn thường giúp đảm bảo mọi thứ được sắp xếp dễ dàng hơn:

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()

8
Câu trả lời hữu ích. Nếu bất cứ ai tình cờ khác trên nó, đây là liên kết đến một hướng dẫn bởi Hadley về việc sử dụng XML2: blog.rstudio.com/2015/04/21/xml2
Richard Erickson

9

Bạn có thể thử mã bên dưới:

# 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.