У меня есть несколько XML-документов со следующей структурой:
read_xml(filename, sep = "")) %>% xml_find_all("//_atraso") %>% xml_structure
[[1]]
<_atraso>
<_omsmaximodia [_omsmaximodia]>
<_omsmaximo [_omsmaximo]>
<_omsmedia [_omsmedia]>
...
...
[[32]]
<_atraso>
<_omsmaximo [_omsmaximo]>
<_omsmedia [_omsmedia]>
...
Как можно видеть, родительский тег _atraso имеет дочерний тег _omsmaximodia на некоторых элементах, но не на других (в этом случае в индексе 1 дочерний тег присутствует, а в индексе 32 его нет).
Я хочу прочитать значение _omsmaximodia, если оно присутствует, и 0 или NA в противном случае. Сейчас читаю вот так:
omsmaximodia <- read_xml(filename, sep = "")) %>% xml_find_all("//_omsmaximodia") %>% xml_attr("_omsmaximodia") %>% gsub("\\.","",.) %>% gsub(",",".",.) %>% {as.numeric(.)}
Однако он ничего не читает, когда тег _omsmaximodia отсутствует. Выполнение приведенного выше кода приводит к списку длиной 29, потому что только 29 из 32 элементов имеют тег _omsmaximodia. Мне нужна длина 32, чтение 0 или NA, где его нет.
Я мог бы легко добавить в список NA или 0, но порядок, в котором элементы читаются, имеет значение. То есть, если элемент 30 не имеет тега _omsmaximodia, тогда значение в позиции 30 в списке должно быть NA или 0. Простое добавление 0 или NA в конец списка недопустимо.
Я попытался использовать функции xml_missing и xml_has_attr, чтобы выяснить, какие индексы не содержат тега _omsmaximodia, но эти функции, похоже, не указывают на отсутствующие теги, и я не смог определить индекс, по которому они отсутствуют.
Любые идеи?
Вероятно, вы можете сделать это в двух частях: сначала найдите все узлы _atraso, а затем найдите _omsmaximodia индивидуально внутри каждого из них.





Чтобы сохранить структуру вашего xml-документа, вы можете попробовать применить свою функцию ко всем элементам отдельно. Следующий пример иллюстрирует составленные данные, поскольку вы только набросали структуру данных.
# load packages and read data
library(xml2)
library(purrr)
input <- "<xml>
<_atraso>
<_omsmaximodia></_omsmaximodia>
</_atraso>
<_atraso>
</_atraso>
</xml>"
x <- read_xml(input)
x
#> {xml_document}
#> <xml>
#> [1] <_atraso>\n <_omsmaximodia/>\n</_atraso>
#> [2] <_atraso>\n </_atraso>
Мы можем найти интересующий тег, но при обычном подходе мы не получаем пропущенного значения для второго тега:
x %>%
xml_find_all(".//_omsmaximodia")
#> {xml_nodeset (1)}
#> [1] <_omsmaximodia/>
Чтобы решить эту проблему, мы переходим на один уровень глубже с xml_children, а затем отображаем все элементы. Результатом для второго элемента является пустой набор узлов. Мы можем использовать map_if в сочетании с is_empty, чтобы преобразовать его в пропущенные значения.
x %>%
xml_children() %>%
map(xml_find_all, ".//_omsmaximodia") %>%
map_if (is_empty, ~{.x <- NA})
#> [[1]]
#> {xml_nodeset (1)}
#> [1] <_omsmaximodia/>
#>
#> [[2]]
#> [1] NA
В зависимости от того, что вам нужно сделать, вы можете использовать различные функции для сглаживания или изменения структуры списка.
Обратите внимание, что с этим кодом вторая версия примерно в 4 раза медленнее. Если вы сделаете это несколько раз, это не имеет значения (второй запрос занимает около 0,75 мс, по сравнению с 0,2 мс для первого), но если вы делаете это часто (т. Е. Анализируете много документов), это может сложиться.
У меня была аналогичная проблема, и я выбрал
purrr::mapвместо элементов с чем-то вродеxml %>% map(xml_find_all, "//_omsmaximodia"), но это, очевидно, немного неэффективно. Было бы любопытно, есть ли лучшее решение ...