2011-09-24 17 views
6

Tengo un gran archivo XML que necesito analizar con xmlEventParse in R. Lamentablemente, los ejemplos en línea son más complejos de lo que necesito, y solo quiero marcar una etiqueta de nodo coincidente para almacenar el texto del nodo coincidente (no el atributo), cada texto en una lista separada, vea los comentarios en el siguiente código:Almacenamiento de valores de nodo XML específicos con R xmlEventParse

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 ?? 

Mi pregunta es cómo implementar esta bandera en R (de manera profesional :)? Plus: ¿Cuál es la mejor opción para evaluar N nodos arbitrarios para que coincidan ... if name = "myNodeToMatchN" ... nodos evitando la coincidencia de casos?

my.xml podría ser sólo una ingenua como XML

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

Estaría bien si tuviéramos "my.xml" a mano para probar cosas ... –

Respuesta

6

voy a utilizar fileName de example(xmlEventParse) como un ejemplo reproducible. Tiene etiquetas record que tienen un atributo id y texto que nos gustaría extraer. En lugar de usar handler, iré después del argumento branches. Esto es como un controlador, pero uno tiene acceso al nodo completo en lugar de solo al elemento. La idea es escribir un cierre que tenga un lugar para guardar los datos que acumulamos, y una función para procesar cada rama del documento XML que nos interesa. Comencemos por definir el cierre, para nuestros propósitos, una función que devuelve una lista de funciones

ourBranches <- function() { 

necesitamos un lugar para almacenar los resultados que se acumulan, la elección de un entorno para que los tiempos de inserción son constantes (no una lista, que habría que añadir a y estaría memoria ineficiente)

store <- new.env() 

El analizador evento se espera una lista de funciones que se invoca cuando se descubre una etiqueta a juego. Estamos interesados ​​en la etiqueta record. La función que escribimos recibirá un nodo del documento XML. Queremos extraer un elemento id que usaremos para almacenar los valores (de texto) en el nodo. Agregamos esto a nuestra tienda.

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

Una vez que se procesa el documento, nos gustaría una manera conveniente para recuperar nuestros resultados, así que agregamos una función para nuestros propios fines, independiente de los nodos en el documento

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

y luego terminar el cierre, devolviendo una lista de funciones

list(record=record, getStore=getStore) 
} 

un concepto difícil aquí es que el entorno en el que se define una función es parte de la función, por lo que cada vez que decimos ourBranches() obtenemos una lista de funciones y un nuevo entorno store para mantener nuestros resultados. Para usar, invoque xmlEventParse en nuestro archivo, con un conjunto vacío de controladores de eventos, y acceda a nuestra tienda acumulada.

> 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 " 
2

Para otros que pueden tratar de Lear M.Morgan - aquí está el código completo

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) 
0

El método ramas no conserva el orden de los acontecimientos. En otras palabras, el orden de 'registro' en sucursales $ getStore() almacena es diferente al del archivo xml original. Por otro lado, los métodos del manejador pueden preservar el orden.Aquí está el código:

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" 

Otra ventaja de utilizar los manipuladores es que uno puede capturar estructura jerárquica. En otras palabras, es posible salvar a los antepasados ​​también. Uno de los puntos clave de este proceso es el uso de variables globales, que se pueden asignar con "< < -", en lugar de "< -".

Cuestiones relacionadas