Работа с пустыми узлами XML в R
У меня есть следующий XML-файл (мне не хватает корневого узла, но редактор не позволяет мне - пожалуйста, предположим, что здесь есть корневой узел):
<Indvls>
<Indvl>
<Info lastNm="HANSON" firstNm="LAURIE"/>
<CrntEmps>
<CrntEmp orgNm="ABC INCORPORATED" str1="FOURTY FOUR BRYANT PARK" city="NEW YORK" state="NY" cntry="UNITED STATES" postlCd="10036">
<BrnchOfLocs>
<BrnchOfLoc str1="833 NE 55TH ST" city="BELLEVUE" state="WA" cntry="UNITED STATES" postlCd="98004"/>
</BrnchOfLocs>
</CrntEmp>
</CrntEmps>
</Indvl>
<Indvl>
<Info lastNm="JACKSON" firstNm="SHERRY"/>
<CrntEmps>
<CrntEmp orgNm="XYZ INCORPORATED" str1="3411 GEORGE STREET" city="SAN FRANCISCO" state="CA" cntry="UNITED STATES" postlCd="94105">
<BrnchOfLocs>
</BrnchOfLocs>
</CrntEmp>
</CrntEmps>
</Indvl>
</Indvls>
Используя R, я хочу извлечь следующие столбцы в форме таблицы: (a) lastNm и firstNm из узла /Info - всегда представлены со значениями; (b) orgNm из узла /CrntEmps/CrntEmp - всегда присутствует со значениями; и (c) str1, city, штат из узла /CrntEmps/BrnchOfLocs/BrnchofLoc - может иметь или не иметь значения (в моем примере второй объект НЕ имеет адреса местоположения офиса).
Моя проблема заключается в том, что многие узлы не будут иметь узла BrnchOfLoc. Я хочу создать запись, даже если узлы отсутствуют (в противном случае таблица не сбалансирована, и я получаю ошибку при создании ее во фрейме данных).
Есть мысли или предложения? Я ценю любые материалы.
Приложение: Вот мой код:
xmlGetNodeAttr <- function(n, xp, attr, default=NA) {
ns<-getNodeSet(n, xp)
if(length(ns)<1) {
return(default)
} else {
sapply(ns, xmlGetAttr, attr, default)
}
}
do.call(rbind, lapply(xmlChildren(xmlRoot(doc)), function(x) {
data.frame(
fname=xmlGetNodeAttr(x, "//Info","firstNm",NA),
lname=xmlGetNodeAttr(x, "//Info","lastNm",NA),
orgname=xmlGetNodeAttr(x,"//CrntEmps/CrntEmp[1]","orgNm",NA),
zip=xmlGetNodeAttr(x, "//CrntEmps/CrntEmp[1]/BrnchOfLocs/BrnchOfLoc[1]","city",NA)
)
}))
1 ответ
Вы должны делать
do.call(rbind, lapply(xmlChildren(xmlRoot(doc)), function(x) {
data.frame(
fname=xmlGetNodeAttr(x, "./Info","firstNm",NA),
lname=xmlGetNodeAttr(x, "./Info","lastNm",NA),
orgname=xmlGetNodeAttr(x, "./CrntEmps/CrntEmp[1]","orgNm",NA),
zip=xmlGetNodeAttr(x, "./CrntEmps/CrntEmp[1]/BrnchOfLocs/BrnchOfLoc[1]","city",NA)
)
}))
Обратите внимание на использование ./
скорее, чем //
, Последний будет искать по всему документу, игнорируя текущий узел, который вы lapply
окончен С помощью ./
начнется с текущего x
узел и смотреть только на потомков. Это возвращает
fname lname orgname zip
Indvl LAURIE HANSON ABC INCORPORATED BELLEVUE
Indvl1 SHERRY JACKSON XYZ INCORPORATED <NA>