Comment analyser le XML en trame de données R


103

J'ai essayé d'analyser XML en trame de données R, ce lien m'a beaucoup aidé:

comment créer une trame de données R à partir d'un fichier xml

Mais je n'ai toujours pas pu comprendre mon problème:

Voici mon code:

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

La trame de données que je veux avoir est comme ceci:

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

Je suis coincé à la xmlToDataFrame(), toute aide serait très appréciée, merci.

Réponses:


103

Les données au format XML sont rarement organisées de manière à permettre à la xmlToDataFramefonction de fonctionner. Vous feriez mieux d'extraire tout dans les listes, puis de lier les listes dans un bloc de données:

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

xml_data <- xmlToList(data)

Dans le cas de vos données d'exemple, obtenir l'emplacement et l'heure de début est assez simple:

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

Les données de température sont un peu plus compliquées. Vous devez d'abord accéder au nœud qui contient les listes de températures. Ensuite, vous devez extraire les deux listes, regarder dans chacune d'elles et choisir celle qui a "horaire" comme l'une de ses valeurs. Ensuite, vous devez sélectionner uniquement cette liste mais ne conserver que les valeurs qui ont le libellé «valeur»:

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

94

Utilisez xpath plus directement pour les performances et la clarté.

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

menant à

> 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
Cela devrait vraiment être la réponse acceptée. C'est plus concis et xpath a de bien meilleures performances que l'itération sur des listes.
SchaunW

40

Voici une solution partielle utilisant xml2. La division de la solution en petits morceaux permet généralement de s'assurer que tout est aligné:

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
Réponse utile. Si quelqu'un d'autre tombe dessus, voici le lien vers un tutoriel de Hadley sur l'utilisation de xml2: blog.rstudio.com/2015/04/21/xml2
Richard Erickson

9

Vous pouvez essayer le code ci-dessous:

# 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)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.