Версии этого вопроса задавались раньше, как здесь и здесь. Однако я все еще не могу заставить его работать. Я пытаюсь преобразовать XML-документ во фрейм данных. Проблема в том, что некоторые из переменных не присутствуют для некоторых наблюдений, поэтому я получаю сообщение об ошибке, потому что существует другое количество строк. Мои данные выглядят так:
library("xml2")
library("dplyr")
example <- read_xml(
'
<particDesc>
<person role="participant" sameAs="#P484" xml:id="EDcon250_S1">
<age value="3">35-49</age>
<sex value="1">male</sex>
<occupation>waiter</occupation>
<langKnowledge>
<langKnown level="L1" tag="ita"/>
</langKnowledge>
</person>
<person role="participant" sameAs="#P485" xml:id="EDcon250_S7">
<age value="0">unknown</age>
<sex value="2">female</sex>
<occupation>waitress</occupation>
<langKnowledge>
<langKnown level="L1" tag="ger-AT"/>
</langKnowledge>
</person>
<person role="participant" sameAs="#P465" xml:id="EDcon250_S2">
<age value="2">25-34</age>
<sex value="2">female</sex>
<langKnowledge>
<langKnown level="L1" tag="ger-AT"/>
<langKnown level="L1" tag="eng-US"/>
</langKnowledge>
</person>
</particDesc>
')
Я использую пакет Wickham xml2
для чтения xml. Я бы предпочел использовать этот пакет, но был бы открыт для использования XML
, если это лучший (или единственный) способ решения этой проблемы. В любом случае мой код следующий:
participants <- xml_find_all(example, './/person[@role = "participant"]')
extract_participants <- function(div){
id <- xml_attr(div, "id")
same_as <- xml_attr(div, "sameAs")
role <- xml_attr(div, "role")
age <- xml_find_all(div, ".//age") %>% xml_text()
sex <- xml_find_all(div, ".//sex") %>% xml_text()
occupation <- xml_find_all(div, ".//occupation") %>% xml_text()
data_frame(id, same_as,role, age, sex, occupation)
}
parts_ls <- lapply(participants, extract_participants)
participants_df <- do.call(rbind, parts_ls)
Проблема в этом конкретном случае касается переменной occupation
(у третьего лица ее нет), но в моих фактических данных это также может быть одна из других переменных. Как я уже сказал, я вижу, что этот вопрос задавался раньше, но я мог заставить любое из предложений работать (вероятно, из-за того, что я не до конца понял решение). В конечном счете, я хотел бы, чтобы NA возвращались всякий раз, когда отсутствует конкретный узел (поэтому переменная occupation
для третьего лица будет NA
.
При редактировании: альтернативная версия XML
library("XML")
library("magrittr")
example2 <- xmlParse(
'
<particDesc>
<person role="participant" sameAs="#P484" xml:id="EDcon250_S1">
<age value="3">35-49</age>
<sex value="1">male</sex>
<occupation>waiter</occupation>
<langKnowledge>
<langKnown level="L1" tag="ita"/>
</langKnowledge>
</person>
<person role="participant" sameAs="#P485" xml:id="EDcon250_S7">
<age value="0">unknown</age>
<sex value="2">female</sex>
<occupation>waitress</occupation>
<langKnowledge>
<langKnown level="L1" tag="ger-AT"/>
</langKnowledge>
</person>
<person role="participant" sameAs="#P465" xml:id="EDcon250_S2">
<age value="2">25-34</age>
<sex value="2">female</sex>
<langKnowledge>
<langKnown level="L1" tag="ger-AT"/>
<langKnown level="L1" tag="eng-US"/>
</langKnowledge>
</person>
</particDesc>
')
example_root <- xmlRoot(example2)
process <- function(x){
id <- xmlGetAttr(x, "id")
role <- xmlGetAttr(x, "role")
age <- getNodeSet(x, ".//age") %>% xmlSApply(xmlValue)
sex <- getNodeSet(x, ".//sex") %>% xmlSApply(xmlValue)
#occupation <- getNodeSet(x, ".//occupation") %>% xmlSApply(xmlValue)
data.frame(id = id,
role = role,
#occupation = occupation,
age = age,
sex = sex,
stringsAsFactors = FALSE)
}
ls <- xpathApply(example_root, "//person", process)
df <- do.call(rbind, ls)
Просто раскомментируйте occupation
, чтобы увидеть проблему.