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) и запустите его вручную. Объект "дерево" будет тогда списком длиной 1, потому что функция xml_find_all() нашла узел с именем "dossiernr" (третий узел в наборе "data"), потому что текст внутри этого узла - "ExampleText", Вы можете проверить это, набрав xml_text(data[[3]]) в консоли, которая равна xml_text(tree[[1]]), Вот как это должно работать.

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

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

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