2013-12-11 4 views
2

Я пытаюсь преобразовать xml-файл из архива Федерального регистра США в кадр данных, где каждая строка соответствует определенному действию (например, Уведомление, Правило, Предлагаемое правило) и каждый столбец содержит атрибут, связанный с этим действием (например, тип агентства, субъект и т. д.). Я попробовал следующее:Преобразование (возможно, искаженное) xml в Data Frame в R

> setwd("C:/Users/mwilliamson/Desktop/FedReg/2000/01/") 
> url = "FR-2000-01-18.xml" 
> doc <- xmlInternalTreeParse("FR-2000-01-18.xml") 
> doc_list <- xmlToList(doc) 
> library(plyr) 
> j <- ldply(doc_list, data.frame) 

Однако, он возвращает ошибку:

Error in data.frame(SECTNO = "§ 831.502", SUBJECT = "Automatic separation; 
exemption.", : 
arguments imply differing number of rows: 1, 0 

Оказывается, что количество пустых значений и различие в длине переменных создают проблему, как R обрабатывает XML (возможно, я ошибаюсь здесь, не так много опыта с пакетом xml). Я думал, что возможно использовать файл схемы (.xsd), чтобы избежать этого, но неясно, как я использую схему с xmlToList. По сути, я ищу «лучший» способ обработать xml в описываемый мной фрейм данных и заполнить любые пустые ячейки NA. Я загрузил схемы и пример файла для:

https://www.dropbox.com/sh/pluje12t185w1v2/ys1xHzilQO

Любая помощь вы можете предоставить было бы здорово !!

UPDATE: Я также попытался:

xmlToDataFrame(doc, colClasses = character, homogeneous = NA) 

но получают следующее:

Error: duplicate subscripts for columns 

Опять же, большое спасибо за любую помощь вы могли бы предложить.

UPDATE: Кажется, что узел/AGENCY - это то, где данные начинают фактически соответствовать формату, который я пытаюсь создать; однако я не могу извлечь всю оставшуюся часть данных (т. е. я могу получить один столбец с 115 документами, идентифицирующими агентство, но не могу получить остальную информацию, связанную с этими 115 записями). Я пробовал следующее:

out <- getNodeSet(doc, "//*", fun=xmlToList) 
df <- data.frame(do.call(rbind, out)) 
head(df) 

, но он, похоже, вызывает R для краха. Я надеюсь, что мои дальнейшие обновления будут вдохновлять кого-то на руку. Еще раз спасибо за любую помощь, которую вы можете дать.

ответ

2

Этот XML беспорядок, и я предполагаю, что вам нужно разобрать каждое действие отдельно.

table(xpathSApply(doc, "//FEDREG/child::node()", xmlName)) 
    DATE NEWPART  NO NOTICES PRESDOCS PRORULES RULES UNITNAME  VOL 
     12  6  12  1  3  1  1  12  12 

table(xpathSApply(doc, "//NOTICES/child::node()", xmlName)) 
    NOTICE 
     92 

Получите уведомления с помощью getNodeSet

z <- getNodeSet(doc, "//NOTICE") 
z[[1]] 
# check node names 
sapply(z, xmlSApply, xmlName) 
x <- xmlToDataFrame(z) 
dim(x) 
[1] 92 4 

Так это затирание много деталей из PREAMB и SUPLINFO, поэтому вам может понадобиться, чтобы разобрать эти узлы отдельно.

Если вы просто возьмете PREAMB, это тоже беспорядок ...

z2 <- getNodeSet(doc, "//NOTICE/PREAMB") 
# check node names and notice different formats 
sapply(z2, xmlSApply, xmlName) 
## and count 
sort(table(unlist(sapply(z2, xmlSApply, xmlName)))) 
AUTH BILCOD  NOTE GPOTABLE STARS PRTPAGE  DATE  FTNT  GPH EFFDATE  ADD DATES  FP  SIG DEPDOC EXTRACT  SUM 
    2  3  3  5  5  8  15  15  15  16  19  24  32  37  45  47  52 
AGY FURINF SUBAGY  ACT AGENCY SUBJECT  HD  P 
    54  54  55  57  92  92  103  663 

Я вижу три различных формата здесь, так xmlToDataFrame будет работать с некоторыми узлами, но не все

x <- xmlToDataFrame(z2[1:4]) 

Сравните эти 10 столбцов результатов от ldply в коде

doc_list <- getNodeSet(doc, "//NOTICE/PREAMB", fun=xmlToList) 
## this returns 31 columns since it grabs every child node... 
j <- ldply(doc_list[1:4], data.frame) 
names(j) 

I подумайте, что иногда лучше просто пробивать результаты getNodeSet и анализировать то, что вам нужно, не забудьте добавить NA, если узел отсутствует (используя здесь функцию xp). Посмотрите? GetNodeSet на создание вспомогательных документов и исправление утечки памяти с помощью бесплатного, но, возможно, что-то вроде этого для наиболее распространенного формата. Вы можете добавить проверки и захватить дополнительные столбцы для уведомлений с большим количеством HD, EXTRACT и P-тэгов.

xp <- function (doc, tag){ 
    n <- xpathSApply(doc, tag, xmlValue) 
    if (length(n) > 0) 
     # paste multiple values? BILCOD and probably others.. 
     paste0(n, collapse="; ") 
    else NA 
} 


    z <- getNodeSet(doc, "//NOTICE") 
    n <-length(z) 
    notices <-vector("list",n) 
    for(i in 1:n) 
    { 
    z2<-xmlDoc(z[[i]]) 
    notices[[i]] <- data.frame(
     AGENCY = xp(z2, "//AGENCY"), 
     SUBAGY = xp(z2, "//SUBAGY"), 
     SUBJECT = xp(z2, "//PREAMB/SUBJECT"), ## SUBJECT node in SECTION too, so it helps to be as specific as possible 
     ACT= xp(z2, "//ACT"), 
     SUM = xp(z2, "//SUM"), 
     DATES = xp(z2, "//DATES"), 
     ADD = xp(z2, "//ADD"), 
     FURINF = xp(z2, "//FURINF"), 
     SIG = xp(z2, "//PREAMB/SIG"),  ## SIG in SUPLINF too 
     SUPLINF = xp(z2, "//SUPLINF"), 
     FRDOC = xp(z2, "//FRDOC"), 
     BILCOD = xp(z2, "//BILCOD"), 
     DEPDOC = xp(z2, "//DEPDOC"), 
     PRTPAGE = xp(z2, "//PRTPAGE"), 
     stringsAsFactors=FALSE) 
    free(z2) 
    } 
    x <- do.call("rbind", notices) 
    head(x) 
    table(is.na(x$ACT)) 
    FALSE TRUE 
    57 35 

У вас еще есть колонны, как SUPLINF с большим количеством структурированных данных пюре вместе - вы можете разорвать, что, если нужно ...

table(xpathSApply(doc, "//NOTICE/SUPLINF/child::node()", xmlName)) 

AMDPAR APPENDIX  AUTH BILCOD  DATE EXTRACT  FP  FTNT  GPH GPOTABLE  HD LSTSUB  P PRTPAGE  SIG  text 
    1  1  10  1  4  10  23  31  10  12  186  1  783  4  52  1 

xpathSApply(doc, "//NOTICE/SUPLINF/GPH", xmlValue) 
[1] "EN18JA00.000" "EN18JA00.001" "EN18JA00.002" "EN18JA00.003" "EN18JA00.004" "EN18JA00.005" "EN18JA00.006" "EN18JA00.007" "EN18JA00.008" "EN18JA00.009" 
## since SIG is in PREAMB and SUPLINF, you may want to parse that separately 
xpathSApply(doc, "//NOTICE/SUPLINF/SIG", xmlValue) 
+0

Это очень полезно. Спасибо. Я не понимаю, как использовать последний бит кода для разрыва SUPLINFO. Я получаю подсчет количества «NA» в таблице, но я не знаю, какие следующие шаги программирования. Спасибо за любую дополнительную информацию, которую вы можете дать. –

+0

Глядя на это более близко, вы, вероятно, согласны с надписью blob. Я добавил дополнительный код в конце моего ответа, чтобы проверить дочерние узлы, чтобы вы могли также захватить один или несколько из них, если это необходимо, вот и все. –

+0

Отлично! Это в сочетании с циклом будет работать для того, что мне нужно. спасибо –

Смежные вопросы