xml2: xml_text () возвращает разные значения в зависимости от того, запущен ли он вручную

В настоящее время я работаю над проектом, в котором применяю интеллектуальный анализ текста к большому количеству файлов xml. Я использую пакет xml2 для обработки xml и пакет stringr для обработки большинства задач интеллектуального анализа текста.

У меня странная проблема. Некоторые из xml-документов содержат странные символы пробела, которые мешают работе, поэтому мне нужно сначала заменить эти символы пробела обычными пробелами. Для этого я беру все узлы из xml-документа, извлекаю текст, изменяю его, а затем присваиваю измененные строки обратно узлам, например: xml_text(node) <- str_replace_all(xml_text(node), "[:space:]", " "), что успешно изменяет символы пробела. Это упрощенная версия моего кода:

# required libraries
require(xml2)
require(stringr)

testfunctie <- function(xmlstring)
{
  # turn string into xml nodeset
  data<-read_xml(xmlstring)
  # take every node separately
  data<-xml_find_all(data, "//*")
  browser()
  # replace weird space characters by regular ones
  for (i in 1:length(data))
  {
    xml_text(data[[i]]) <- str_replace_all(xml_text(data[[i]]), "[:space:]", " ")
  }
  # find all nodes containing a certain text
  tree <- xml_find_all(data, "//dossiernr[text()='ExampleText']")
  browser()
  return(tree)
}

# XML example
exampleXML<-"<dossier>
<dossiernummer>
<dossiernr>ExampleText</dossiernr>
</dossiernummer>
<titel>AnotherPieceOfExampleText</titel>
</dossier>"

mvt <- testfunctie(exampleXML)

Обычно это работает так, как должно, но в некоторых случаях возникает странная проблема, и текст, извлеченный с помощью xml_text (), также содержит текст из других узлов. В этом можно убедиться, запустив приведенный выше код. Когда срабатывает первый оператор browser (), выберите оставшийся код до второго оператора browser () (строки 13-18) и запустите его вручную. Объект "tree" тогда будет списком длиной 1, потому что функция xml_find_all () нашла узел с именем "dossiernr" (третий узел в наборе узлов "data"), потому что текст внутри этого узла - "ExampleText" . Вы можете проверить это, набрав в консоли xml_text(data[[3]]), что равно xml_text(tree[[1]]). Вот как это должно работать.

Однако, если вместо этого вы нажмете «продолжить» после первого оператора браузера и автоматически запустите оставшийся код, когда вы перейдете ко второму оператору браузера, «дерево» будет списком длиной 0. Если вы затем наберете xml_text(data[[3]]), это окажется что текст внутри узла был заменен на «ExampleTextAnotherPieceOfExampleText» вместо просто «ExampleText». Текст внутри другого узла (узел с именем "title") добавляется к нему.

Поэтому по какой-то причине этот код ведет себя по-разному в зависимости от того, запускаю ли я его вручную или автоматически. Может ли кто-нибудь помочь мне понять, почему это происходит, и как я могу решить эту проблему? Заранее спасибо.


person Frank van Dorp    schedule 14.03.2018    source источник
comment
Похоже на ошибку ... Может быть, отправить как проблему github.com/r-lib/xml2/issues   -  person Jack Brookes    schedule 15.03.2018


Ответы (1)


Функция xml_text возвращает весь текст в родительских и всех листовых узлах, поэтому некоторые узлы являются объединенными значениями. Кажется, это непоследовательное поведение.

Мое предложение вместо того, чтобы пытаться работать с каждым узлом и заменить текст, выполнить глобальную замену всего xml-документа с помощью str_replace_all, а затем повторно прочитать данные обратно как xml.

# XML example
exampleXML<-"<dossier>
<dossiernummer>
<dossiernr>ExampleText</dossiernr>
</dossiernummer>
<titel>AnotherPieceOfExampleText</titel>
</dossier>"

data<-read_xml(exampleXML)

data<-str_replace_all(data, "[:space:]", " ")

data<-read_xml(data)
person Dave2e    schedule 15.03.2018