R & xml2: поиск элементов по определенному текстовому значению, сохранение всех дочерних значений в data.frame

Я работаю с регулярно обновляемыми XML-отчетами, и я хотел бы автоматизировать процесс настройки с помощью R & xml2.

Вот ссылка на весь пример файла. Вот образец XML:

<?xml version="1.0" ?>
<riDetailEnrolleeReport xmlns="http://vo.edge.fm.cms.hhs.gov">
    <includedFileHeader>
        <outboundFileIdentifier>f2e55625-e70e-4f9d-8278-fc5de7c04d47</outboundFileIdentifier>
        <cmsBatchIdentifier>RIP-2015-00096</cmsBatchIdentifier>
        <cmsJobIdentifier>16220</cmsJobIdentifier>
        <snapShotFileName>25032.BACKUP.D03152016T032051.dat</snapShotFileName>
        <snapShotFileHash>20d887c9a71fa920dbb91edc3d171eb64a784dd6</snapShotFileHash>
        <outboundFileGenerationDateTime>2016-03-15T15:20:54</outboundFileGenerationDateTime>
        <interfaceControlReleaseNumber>04.03.01</interfaceControlReleaseNumber>
        <edgeServerVersion>EDGEServer_14.09_01_b0186</edgeServerVersion>
        <edgeServerProcessIdentifier>8</edgeServerProcessIdentifier>
        <outboundFileTypeCode>RIDE</outboundFileTypeCode>
        <edgeServerIdentifier>2800273</edgeServerIdentifier>
        <issuerIdentifier>25032</issuerIdentifier>
    </includedFileHeader>
    <calendarYear>2015</calendarYear>
    <executionType>P</executionType>
    <includedInsuredMemberIdentifier>
        <insuredMemberIdentifier>ARS001</insuredMemberIdentifier>
        <memberMonths>12.13</memberMonths>
        <totalAllowedClaims>1000.00</totalAllowedClaims>
        <totalPaidClaims>100.00</totalPaidClaims>
        <moopAdjustedPaidClaims>100.00</moopAdjustedPaidClaims>
        <cSRMOOPAdjustment>0.00</cSRMOOPAdjustment>
        <estimatedRIPayment>0.00</estimatedRIPayment>
        <coinsurancePercentPayments>0.00</coinsurancePercentPayments>
        <includedPlanIdentifier>
            <planIdentifier>25032VA013000101</planIdentifier>
            <includedClaimIdentifier>
                <claimIdentifier>CADULT4SM00101</claimIdentifier>
                <claimPaidAmount>100.00</claimPaidAmount>
                <crossYearClaimIndicator>N</crossYearClaimIndicator>
            </includedClaimIdentifier>
        </includedPlanIdentifier>
    </includedInsuredMemberIdentifier>
    <includedInsuredMemberIdentifier>
        <insuredMemberIdentifier>ARS002</insuredMemberIdentifier>
        <memberMonths>9.17</memberMonths>
        <totalAllowedClaims>0.00</totalAllowedClaims>
        <totalPaidClaims>0.00</totalPaidClaims>
        <moopAdjustedPaidClaims>0.00</moopAdjustedPaidClaims>
        <cSRMOOPAdjustment>0.00</cSRMOOPAdjustment>
        <estimatedRIPayment>0.00</estimatedRIPayment>
        <coinsurancePercentPayments>0.00</coinsurancePercentPayments>
        <includedPlanIdentifier>
            <planIdentifier>25032VA013000101</planIdentifier>
            <includedClaimIdentifier>
                <claimIdentifier></claimIdentifier>
                <claimPaidAmount>0</claimPaidAmount>
                <crossYearClaimIndicator>N</crossYearClaimIndicator>
            </includedClaimIdentifier>
        </includedPlanIdentifier>
    </includedInsuredMemberIdentifier>
</riDetailEnrolleeReport>

Я хотел бы:

  1. Прочитать XML в R
  2. Найдите конкретный insuredMemberIdentifier
  3. Извлеките planIdentifier и все данные ClaimIdentifier, связанные с идентификатором участника в (2).
  4. Сохраните весь текст и значения для insuredMemberIdentifier, planIdentifier, ClaimIdentifier и ClaimPaidAmount в data.frame со строкой для каждого уникального идентификатора заявки (идентификатор участника для идентификатора заявки - от 1 до многих)

Пока что я выполнил 1, и я нахожусь примерно в 2:

## Step 1 ##
ride <- read_xml("/Users/temp/Desktop/RIDetailEnrolleeReport.xml")

## Step 2 -- assume the insuredMemberIdentifier of interest is 'ARS001' ##
memID <- xml_find_all(ride, "//d1:insuredMemberIdentifier[text()='ARS001']", xml_ns(ride))

[Я знаю, что затем могу использовать xml_text() для извлечения текста элемента.]

После кода на шаге 2 выше я попытался использовать xml_parent(), чтобы найти родительский узел insuredMemberIdentifier, сохранив его как переменную, а затем повторив шаг 2 для получения информации о заявке на этом сохраненном узле переменной.

node <- xml_parent(memID)
xml_find_all(node, "//d1:claimIdentifier", xml_ns(ride))

Но это просто приводит к извлечению всех идентификаторов требований из глобального файла.

Мы будем очень благодарны за любую помощь / информацию о том, как перейти к шагу 4 выше. Заранее спасибо.


person piginthecity    schedule 20.05.2016    source источник
comment
Это классическая проблема XPath. / в начале XPath всегда означает абсолютный путь. Добавьте ., чтобы сделать его относительным: .//d1:claimIdentifier (не могу помочь с r частью вашего вопроса)   -  person har07    schedule 20.05.2016


Ответы (1)


Приносим извинения за поздний ответ, но для потомков импортируйте данные, как указано выше, с помощью xml2, а затем проанализируйте файл xml по идентификатору, как указано в har07.

# output object to collect all claims
res <- data.frame(
    insuredMemberIdentifier = rep(NA, 1), 
    planIdentifier = NA, 
    claimIdentifier = NA, 
    claimPaidAmount = NA)
# vector of ids of interest
ids <- c('ARS001')
# indexing counter
starti <- 1
# loop through all ids
for (ii in seq_along(ids)) {
    # find ii-th id
    ## Step 2 -- assume the insuredMemberIdentifier of interest is 'ARS001' ##
    memID <- xml_find_all(x = ride, 
        xpath = paste0("//d1:insuredMemberIdentifier[text()='", ids[ii], "']"))
    # find node for 
    node <- xml_parent(memID)
    # as har07's comment find claim id within this node
    cid <- xml_find_all(node, ".//d1:claimIdentifier", xml_ns(ride))
    pid <- xml_find_all(node, ".//d1:planIdentifier", xml_ns(ride))
    cpa <- xml_find_all(node, ".//d1:claimPaidAmount", xml_ns(ride))
    # add invalid data handling if necessary
    if (length(cid) != length(cpa)) {
        warning(paste("cid and cpa do not match for", ids[ii]))
        next
    }
    # collect outputs 
    res[seq_along(cid) + starti - 1, ] <- list(
        ids[ii], 
        xml_text(pid),
        xml_text(cid),
        xml_text(cpa))
    # adjust counter to add next id into correct row
    starti <- starti + length(cid)
}
res
#   insuredMemberIdentifier   planIdentifier claimIdentifier claimPaidAmount
# 1                  ARS001 25032VA013000101  CADULT4SM00101          100.00
person CSJCampbell    schedule 19.10.2018