Использование пакета R xml2
Мне удалось разобрать и преобразовать прикрепленный ниже XML-файл в фрейм данных. Код, который я использую, является следующим
require(magrittr)
require(xml2)
res <- read_xml("~/xml_file.xml", as = "parsed")
vars <- res %>% xml_find_first("./d1:resultProperties") %>%
xml_children() %>% xml_text()
size <- res %>% xml_find_first("./d1:resultsInformation") %>%
xml_children() %>% xml_text() %>% as.numeric()
orgUnits <- res %>% xml_find_first("d1:results") %>%
xml_children()
В узле resultProperties можно заранее определить, какая переменная там находится; в то время как узел resultsInformation дает счет. Я использовал эту полезную информацию, когда пытался найти стратегию, чтобы преобразовать ее в фрейм данных, хранящий эти значения в переменных вары а также размер.
Для фактического преобразования в dataframe я нашел два метода:
Метод 1: (так как я знаю, перед началом переменные включены) пройти каждый организационное подразделение узел и извлекать по одной переменной за раз из каждого узла
# method 1 - extract one variable at a time from each orgUnit node
df <- data.frame(matrix(NA, nrow = size, ncol = length(vars)))
for (i in 1:length(vars)) {
df[ ,i] = xml_text(xml_find_first(orgUnits, paste0( "d1:", vars[i])))
}
метод 2: извлечь каждый организационное подразделение узел полностью при обходе DOM
# method 2.2
f <- function(x){
a <- xml_children(x)
text <- xml_text(a)
names(text) <- xml_name(a)
class(text) <- "list"text
}
df <- map_dfr(orgUnits, f)
Сложность в том, что я не могу просто использовать такую функцию, как xml_find_all
так как не каждый организационное подразделение узел содержит все переменные. И в методе 2 мне пришлось назначить учебный класс = список в противном случае bind_rows бы жаловался.
Я очень доволен обоими решениями: метод 2 немного быстрее, чем метод 1. Однако, для анализа ~ 8’000 orgUnits требуемое время составляет от 4,50 до 6,30 секунд. Мне нужно использовать эту процедуру для большого файла XML (~ 1’000’000 orgUnits) и выступления действительно плохие.
Правовая оговорка: я — полный новичок в том, что я объясняю ниже, пожалуйста, прости небрежную номенклатуру.
Я хотел бы использовать Rcpp
интегрировать код C ++ в мой Rscript. Узкое место моего кода начинается, когда я извлекаю orgUnits узлы: переменная orgUnits, которую я создаю, не является указатель больше (как, например, переменная res). Я полагаю, что работа с указателями намного быстрее, чем работа со списком R объектов.
Поэтому я хотел бы написать специальный код C ++, возможно, используя выражения xpath для извлечения текста из узлов. НО я совсем не уверен в C ++. У кого-нибудь есть предложения о том, как написать такой код на C ++ или, возможно, написать более эффективный код на R?
заранее большое спасибо
<orgUnitsResponse>
<filters>
<nace>
<ns2:in>
<ns2:value>64_11</ns2:value>
<ns2:value>64_19</ns2:value>
</ns2:in>
</nace>
</filters>
<resultProperties>
<resultProperty>id</resultProperty>
<resultProperty>birth_date</resultProperty>
<resultProperty>close_date</resultProperty>
<resultProperty>code</resultProperty>
<resultProperty>name</resultProperty>
<resultProperty>nace</resultProperty>
<resultProperty>postal_code</resultProperty>
<resultProperty>city</resultProperty>
</resultProperties>
<resultsInformation>
<count>4</count>
</resultsInformation>
<results>
<orgUnit>
<id>1</id>
<birth_date>1998-01-01</birth_date>
<close_date>9999-12-31</close_date>
<code>AT00100</code>
<name>Oesterreichische Nationalbank</name>
<nace>64_11</nace>
<postal_code>1090</postal_code>
<city>Wien</city>
</orgUnit>
<orgUnit>
<id>128</id>
<birth_date>1998-01-01</birth_date>
<close_date>9999-12-31</close_date>
<code>AT20607</code>
<name>Sparkasse Bludenz Bank AG</name>
<nace>64_19</nace>
<postal_code>6700</postal_code>
<city>Bludenz</city>
</orgUnit>
<orgUnit>
<id>130</id>
<birth_date>1998-01-01</birth_date>
<close_date>9999-12-31</close_date>
<code>AT20702</code>
<name>Sparkasse Feldkirchen/Kärnten</name>
<nace>64_19</nace>
<postal_code>9560</postal_code>
<city>Feldkirchen (Ktn.)</city>
</orgUnit>
<orgUnit>
<id>131</id>
<birth_date>1998-01-01</birth_date>
<close_date>9999-12-31</close_date>
<code>AT20706</code>
<name>Kärntner Sparkasse Aktiengesellschaft</name>
<nace>64_19</nace>
<postal_code>9020</postal_code>
<city>Klagenfurt</city>
</orgUnit>
</results>
</orgUnitsResponse>
Задача ещё не решена.
Других решений пока нет …