Более прямой способ создать список фреймов данных из файла XML?

SDMX (Обмен статистическими данными и метаданными) - это грамматика XML, которая определяет стандарт для обмена статистическими данными. Он использует файлы, называемые описанием определения структуры набора данных (DSD), чтобы передать структуру набора данных. Среди прочего, DSD содержит узел Codelists, который состоит из Codelist элементов, которые, в свою очередь, являются родительскими для Code и Name элемента и атрибута. В настоящее время я пытаюсь разобрать эти списки кодов файла DSD, запрошенного из интерфейс REST Eurostats в список фреймов данных в R, используя следующий код:

library(XML);library(RCurl)

# REST resource for DSD of nama_gdp_c
# downloading, parsing XML an setting root
file <- "http://ec.europa.eu/eurostat/SDMX/diss-web/rest/datastructure/ESTAT/DSD_nama_gdp_c"
content <- getURL(file, httpheader = list('User-Agent' = 'R-Agent'))
root <- xmlRoot(xmlInternalTreeParse(content, useInternalNodes = TRUE))

# get Nodeset of Codelists and its length
nodes <- getNodeSet(root,"//str:Codelist")
nn <- length(nodes)

# Create nested List of all Codes and Names
codelistAll <- lapply(seq(nn),function(i){
  xpathSApply(root,paste0("//str:Codelist[",i,"]/str:Code"),xmlGetAttr, "id")
})

namelistAll <- lapply(seq(nn),function(i){
  xpathSApply(root,paste0("//str:Codelist[",i,"]/str:Code/com:Name"),xmlValue)
})

# Create a list of dataframes from the nested lists
alldfList <-lapply(seq(nn),function(i) data.frame(codes=codelistAll[[i]],names=namelistAll[[i]]))

# Name the list items like the nodes
names(alldfList)  <- sapply(nodes, xmlGetAttr,"id")

Это дает alldfList, список фреймов данных, который я искал.

> str(alldfList)
List of 6
 $ CL_FREQ      :'data.frame':  6 obs. of  2 variables:
  ..$ codes: Factor w/ 6 levels "A","D","H","M",..: 2 6 5 1 4 3
  ..$ names: Factor w/ 6 levels "Annual","Daily",..: 2 6 4 1 3 5
 $ CL_GEO       :'data.frame':  49 obs. of  2 variables:
  ..$ codes: Factor w/ 49 levels "AT","BA","BE",..: 22 21 20 10 16 15 14 13 12 11 ...
  ..$ names: Factor w/ 49 levels "Austria","Belgium",..: 19 18 17 16 15 14 13 12 11 10 ...

Хотя это делает свою работу, я чувствую, что для этого должен быть более простой синтаксис. Особенно неудобно использование paste0 и окончательное присвоение имён. Я читал документацию к пакету XML и подозреваю, что это какая-то операция на xlmChildren, но я не могу понять, как это сделать. Есть ли у кого-нибудь предложения по каноническому способу выполнения этой операции? Любое предложение будет принято с благодарностью.


person Tungurahua    schedule 24.07.2014    source источник
comment
Я всегда начинаю с тех, которые возвращают данные, xmlToDataFrame(), readHTMLTable() и т. Д.   -  person Rich Scriven    schedule 03.09.2014


Ответы (2)


Вы можете получить data.frames прямо из узлов, но вам нужно использовать пространство имен

ns <- c(str="http://www.sdmx.org/resources/sdmxml/schemas/v2_1/structure")

alldfList <- lapply(nodes, function(x){ data.frame(
  codes= xpathSApply(x, ".//str:Code" , xmlGetAttr, "id", namespaces=ns),
  names= xpathSApply(x, ".//str:Code" , xmlValue, namespaces=ns) )})

names(alldfList)  <- sapply(nodes, xmlGetAttr,"id")
person Chris S.    schedule 25.07.2014
comment
Большой! Работает как шарм и определенно более лаконичен и компактен, чем исходный код. Мне потребовалось несколько минут, чтобы понять, что пространство имен удаляется из исходного XML при использовании getNodeSet. Знаете ли вы случайно, есть ли прямой способ сохранить пространства имен при разделении узлов? - person Tungurahua; 26.07.2014

Поскольку вы пытаетесь читать файлы SDMX-ML в R, вы можете попробовать пакет rsdmx, размещенный в Github. Пакет доступен для загрузки в CRAN, а последняя версия позволяет вам читать определения структуры данных (DSD) и компоненты, включая списки кодов, концепции и семейства ключей.

Для установки, если вы все равно можете легко установить его из Github, используя следующее:

require(devtools)
install_github("rsdmx", "opensdmx")

Взяв ваш пример со списками кодов, вы можете легко принудительно преобразовать списки кодов SDMX в data.frame, выполнив следующие действия:

require(rsdmx)
file <- "http://ec.europa.eu/eurostat/SDMX/diss-web/rest/datastructure/ESTAT/DSD_nama_gdp_c"
sdmx <- readSDMX(file)

#get the list of codelist Id
codelists <- sapply(sdmx@codelists, function(x) x@id)

#get some specific codelist as data.frame
codelist <- as.data.frame(sdmx, codelistId = "CL_GEO")
head(codelist)

То же самое можно сделать для SDMX Concepts / ConceptSchemes, полных определений структуры данных (DSD) и, конечно, для наборов данных SDMX. Дополнительные примеры см. На rsdmx wiki.

Надеюсь это поможет!

person eblondel    schedule 29.08.2014