Хранение определенных значений узла XML с помощью R xmlEventParse

У меня есть большой файл XML, который мне нужно проанализировать с помощью xmlEventParse в R. К сожалению, онлайн-примеры более сложны, чем мне нужно, и я просто хочу пометить соответствующий тег узла, чтобы сохранить текст сопоставленного узла (не атрибут), каждый текст в отдельном списке, см. комментарии в коде ниже:

library(XML)
z <- xmlEventParse(
    "my.xml", 
    handlers = list(
        startDocument   =   function() 
        {
                cat("Starting document\n")
        },  
        startElement    =   function(name,attr) 
        {
                if ( name == "myNodeToMatch1" ){
                    cat("FLAG Matched element 1\n")
                }
                if ( name == "myNodeToMatch2" ){
                    cat("FLAG Matched element 2\n")
                }
        },
        text            =   function(text) {
                if ( # Matched element 1 .... )
                    # Store text in element 1 list
                if ( # Matched element 2 .... )
                    # Store text in element 2 list
        },
        endDocument     =   function() 
        {
                cat("ending document\n")
        }
    ),
    addContext = FALSE,
    useTagName = FALSE,
    ignoreBlanks = TRUE,
    trim = TRUE)
z$ ... # show lists ??

Мой вопрос в том, как реализовать этот флаг в R (профессионально :)? Плюс: какой лучший выбор для оценки N произвольных узлов для соответствия... если имя = "myNodeToMatchN"... узлы, избегающие сопоставления регистра?

my.xml может быть просто наивным XML, например

<A>
  <myNodeToMatch1>Text in NodeToMatch1</myNodeToMatch1>
  <B>
    <myNodeToMatch2>Text in NodeToMatch2</myNodeToMatch2>
    ...
  </B>
</A>

person Veronica    schedule 24.09.2011    source источник
comment
Было бы неплохо, если бы у нас был my.xml под рукой, чтобы попробовать...   -  person Roman Luštrik    schedule 24.09.2011


Ответы (3)


Я буду использовать fileName из example(xmlEventParse) в качестве воспроизводимого примера. У него есть теги record с атрибутом id и текст, который мы хотели бы извлечь. Вместо того, чтобы использовать handler, я буду использовать аргумент branches. Это похоже на обработчик, но у него есть доступ ко всему узлу, а не только к элементу. Идея состоит в том, чтобы написать замыкание, в котором есть место для хранения данных, которые мы собираем, и функция для обработки каждой ветки интересующего нас XML-документа. Итак, давайте начнем с определения замыкания — для наших целей это функция, которая возвращает список функций

ourBranches <- function() {

Нам нужно место для хранения результатов, которые мы накапливаем, выбирая среду так, чтобы время вставки было постоянным (а не список, к которому нам пришлось бы добавлять и который был бы неэффективным с точки зрения памяти).

    store <- new.env() 

Анализатор событий ожидает список функций, которые будут вызываться при обнаружении соответствующего тега. Нас интересует тег record. Функция, которую мы напишем, получит узел XML-документа. Мы хотим извлечь элемент id, который будем использовать для хранения (текстовых) значений в узле. Мы добавляем их в наш магазин.

    record <- function(x, ...) {
        key <- xmlAttrs(x)[["id"]]
        value <- xmlValue(x)
        store[[key]] <- value
    }

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

    getStore <- function() as.list(store)

а затем завершите закрытие, вернув список функций

    list(record=record, getStore=getStore)
}

Хитрая концепция здесь заключается в том, что среда, в которой определена функция, является частью функции, поэтому каждый раз, когда мы говорим ourBranches(), мы получаем список функций и новую среду store для сохранения наших результатов. Чтобы использовать, вызовите xmlEventParse в нашем файле с пустым набором обработчиков событий и получите доступ к нашему накопленному хранилищу.

> branches <- ourBranches()
> xmlEventParse(fileName, list(), branches=branches)
list()
> head(branches$getStore(), 2)
$`Hornet Sportabout`
[1] "18.7   8 360.0 175 3.15 3.440 17.02  0  0    3 "

$`Toyota Corolla`
[1] "33.9   4  71.1  65 4.22 1.835 19.90  1  1    4 "
person Martin Morgan    schedule 25.09.2011

Для других, кто может попытаться учиться у М. Моргана - вот полный код

fileName = system.file("exampleData", "mtcars.xml", package = "XML")

ourBranches <- function() {
  store <- new.env() 
  record <- function(x, ...) {
    key <- xmlAttrs(x)[["id"]]
    value <- xmlValue(x)
    store[[key]] <- value
  }
  getStore <- function() as.list(store)
  list(record=record, getStore=getStore)
}

branches <- ourBranches()
xmlEventParse(fileName, list(), branches=branches)
head(branches$getStore(), 2)
person userJT    schedule 11.07.2014

Метод ветвей не сохраняет порядок событий. Другими словами, порядок «записи» в хранилищах branch$getStore() отличается от порядка в исходном xml-файле. С другой стороны, методы обработчика могут сохранять порядок. Вот код:

fileName <- system.file("exampleData", "mtcars.xml", package="XML")
records <- new('list')
variable <- new('character')
tag.open <- new('character')
nvar <- 0
xmlEventParse(fileName, list(startElement = function (name, attrs) {
  tagName <<- name
  tag.open <<- c(name, tag.open)
  if (length(attrs)) {
    attributes(tagName) <<- as.list(attrs)
  }
}, text = function (x) {
  if (nchar(x) > 0) {
    if (tagName == "record") {
      record <- list()
      record[[attributes(tagName)$id]] <- x
      records <<- c(records, record)
    } else {
      if( tagName == 'variable') {
        v <- x
        variable <<- c( variable, v)
        nvar <<- nvar + 1
      }
    }
  }
}, endElement = function (name) {
  if( name == 'record') {
    print(paste(tag.open, collapse='>'))
  }
  tag.open <<- tag.open[-1]
}))

head(records,2)
$``Mazda RX4``
[1] "21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4"

$`Mazda RX4 Wag`
[1] "21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4"

variable
[1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear" "carb"

Еще одним преимуществом использования обработчиков является возможность захвата иерархической структуры. Другими словами, можно спасти и предков. Одним из ключевых моментов этого процесса является использование глобальных переменных, которым можно присвоить «‹‹-» вместо «‹-».

person Sangsoo Kim    schedule 03.11.2016