Работа с пустыми узлами 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>
Другие вопросы по тегам