Преобразование XML в dataframe с использованием XML2 — SDMX case

#r #xml #xml-parsing #xml2

#r #xml #xml-синтаксический анализ #xml2

Вопрос:

Пожалуйста, взгляните на reprex в этом вопросе. SDMX — это модель данных для распространения статистических данных, и для ее обработки существуют инструменты на Python и R. SDMX обычно предоставляется в виде XML-файла (в последнее время также в виде файла JSON). Я могу обработать простой пример, приведенный в URL-адресе в reprex, с помощью специальной библиотеки, но я хотел бы понять, что происходит, поэтому я хотел бы воспроизвести конечный результат, используя xml2 и … вот где я бьюсь головой о стену.

Причина в том, что в ближайшем будущем мне, возможно, придется обрабатывать сложные XML-файлы, которые близки к SDMX, но не совсем идентичны, что означает, что мне нужно иметь возможность делать это вручную. Приветствуются любые предложения. Спасибо

 library(tidyverse)
library(xml2)
library(rsdmx)


url <- "https://stats.oecd.org/restsdmx/sdmx.ashx/GetData/FDIINDEX/AUT BEL.4 5 8 9 14.V.INDEX/all?startTime=1997amp;endTime=2019"


##Very easy if I resort to a dedicated library

sdmx <- readSDMX(url, isURL = T)
stats <- as_tibble(sdmx)  ## and I have my nice tibble

print(stats)
#> # A tibble: 130 x 7
#>    LOCATION SECTOR RESTYPE SERIES TIME_FORMAT obsTime obsValue
#>    <chr>    <chr>  <chr>   <chr>  <chr>       <chr>      <dbl>
#>  1 AUT      4      V       INDEX  P1Y         1997           0
#>  2 AUT      4      V       INDEX  P1Y         2003           0
#>  3 AUT      4      V       INDEX  P1Y         2006           0
#>  4 AUT      4      V       INDEX  P1Y         2010           0
#>  5 AUT      4      V       INDEX  P1Y         2011           0
#>  6 AUT      4      V       INDEX  P1Y         2012           0
#>  7 AUT      4      V       INDEX  P1Y         2013           0
#>  8 AUT      4      V       INDEX  P1Y         2014           0
#>  9 AUT      4      V       INDEX  P1Y         2015           0
#> 10 AUT      4      V       INDEX  P1Y         2016           0
#> # … with 120 more rows


xmlobj <- read_xml(url)

## and then I do not know how to proceed...
  

Создано 2020-09-01 пакетом reprex (версия 0.3.0)

Комментарии:

1. Вы можете прочитать исходный код этих функций на github: readSDMX и as.data.frame. SDMXMessageGroup / как.data.frame.SDMXGenericData который вызывается as_tibble .

2. Правильно. Я внимательно посмотрю.

Ответ №1:

Вы должны узнать о XPath. Я даю комментарий в коде, чтобы помочь вам понять:

 library(xml2)
url <- "https://stats.oecd.org/restsdmx/sdmx.ashx/GetData/FDIINDEX/AUT BEL.4 5 8 9 14.V.INDEX/all?startTime=1997amp;endTime=2019"
series <- read_xml(url) %>% xml_ns_strip() %>% xml_find_all("//DataSet/Series") # find all Series nodes
# note that the easiest way to read nodes in this file is to remove the namespaces by xml_ns_strip()
data <- 
  purrr::map_dfr(
    series,
    function(x) {
      data.frame(
        LOCATION = x %>% xml_find_first(".//Value[@concept='LOCATION']") %>% xml_attr("value"), # for each Series node, get the first Value node has 'concept' attribute is 'LOCATION' and extract the 'value' attribute value
        SECTOR = x %>% xml_find_first(".//Value[@concept='SECTOR']") %>% xml_attr("value"),
        RESTYPE = x %>% xml_find_first(".//Value[@concept='RESTYPE']") %>% xml_attr("value"),
        SERIES = x %>% xml_find_first(".//Value[@concept='SERIES']") %>% xml_attr("value"),
        TIME_FORMAT = x %>% xml_find_first(".//Value[@concept='TIME_FORMAT']") %>% xml_attr("value"),
        data.frame(
          Time = x %>% xml_find_all(".//Obs/Time") %>% xml_text(trim = TRUE) %>% as.integer(),
          ObsValue = x %>% xml_find_all(".//Obs/ObsValue") %>% xml_attr("value") %>% as.numeric()
        )
      ) 
    }
    )