2011-09-24 3 views
6

Ho un file XML grande che ho bisogno di analizzare con xmlEventParse in R. Purtroppo on-line esempi sono più complessi di quanto ho bisogno, e voglio solo la bandiera di un tag corrispondente nodo per memorizzare il testo del nodo corrispondente (non attribuire), ogni testo in un elenco separato, vedere i commenti nel codice qui sotto:memorizzare i valori specifici del nodo XML con xmlEventParse di 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 ?? 

la mia domanda è, come implementare questo flag in R (in modo professionale :)? Plus: Qual è la scelta migliore per valutare N nodi arbitrari da abbinare ... se name = "myNodeToMatchN" ... nodi che evitino la corrispondenza dei casi?

my.xml potrebbe essere solo un XML ingenua come

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

Sarebbe bello se avessimo a portata di mano "my.xml" per provare ... –

risposta

6

userò fileName da example(xmlEventParse) come un esempio riproducibile. Sono presenti le tag record che hanno un attributo id e il testo che vorremmo estrarre. Piuttosto che usare handler, andrò dopo l'argomento branches. Questo è come un gestore, ma si ha accesso al nodo completo piuttosto che solo all'elemento. L'idea è di scrivere una chiusura che abbia un posto dove conservare i dati che accumuliamo e una funzione per elaborare ogni ramo del documento XML a cui siamo interessati. Quindi iniziamo definendo la chiusura - per i nostri scopi, una funzione che restituisce un elenco di funzioni

ourBranches <- function() { 

abbiamo bisogno di uno spazio per riporre i risultati che si accumulano, la scelta di un ambiente in modo che i tempi di inserzione sono costanti (non una lista, che avremmo dovuto aggiungere al e sarebbe la memoria inefficiente)

store <- new.env() 

Il parser evento prevede un elenco di funzioni da richiamare quando un tag corrispondente viene scoperto. Siamo interessati al tag record. La funzione che scriviamo riceverà un nodo del documento XML. Vogliamo estrarre un elemento id che useremo per memorizzare i valori (di testo) nel nodo. Li aggiungiamo al nostro negozio.

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

Una volta che il documento viene elaborato, vorremmo un modo conveniente per recuperare i nostri risultati, in modo da aggiungiamo una funzione per i nostri scopi, indipendentemente nodi nel documento

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

e poi concretizzare la chiusura restituendo un elenco di funzioni

list(record=record, getStore=getStore) 
} 

un concetto difficile ecco che l'ambiente in cui è definito funzione è parte della funzione, in modo che ogni volta che diciamo ourBranches() otteniamo un elenco di funzioni e un nuovo ambiente store per mantenere i nostri risultati. Per utilizzare, richiamare xmlEventParse sul nostro file, con un set vuoto di gestori di eventi e accedere al nostro negozio accumulato.

> 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

Per gli altri che potrebbero tentare di Lear M.Morgan - Ecco il codice 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

Il metodo rami non mantiene l'ordine degli eventi. In altre parole, l'ordine di 'record' nei rami $ getStore() memorizza è diverso da quello nel file xml originale. D'altra parte, i metodi del gestore possono conservare l'ordine.Ecco il codice:

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" 

Un altro vantaggio di usare i gestori è che si può catturare struttura gerarchica. In altre parole, è possibile salvare anche gli antenati. Uno dei punti chiave di questo processo è l'uso di variabili globali, che possono essere assegnate con "< < -", anziché "< -".