2011-09-24 14 views
6

Mam duży plik XML, który muszę przeanalizować przy pomocy xmlEventParse in R. Niestety, przykłady on-line są bardziej złożone niż mi potrzebne, i chcę tylko oznaczyć pasujący znacznik węzła do przechowywania dopasowanego tekstu węzła (nie atrybut), każdy tekst na osobnej liście, zobacz komentarze w poniższym kodzie:Przechowywanie określonych wartości węzłów XML za pomocą 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 ?? 

Moje pytanie brzmi, jak zaimplementować tę flagę w R (w profesjonalny sposób :)? Plus: Jaki jest najlepszy wybór do oceny N dowolnych węzłów do dopasowania ... jeśli nazwa = "mójNodeToMatchN" ... węzłów unikając dopasowania sprawy?

my.xml może być po prostu naiwny XML jak

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

Byłoby miło, gdybyśmy mieli "mój.xml" przydatny do wypróbowania rzeczy ... –

Odpowiedz

6

użyję fileName z example(xmlEventParse) jako powtarzalny przykład. Ma znaczniki record, które mają atrybut id i tekst, który chcemy wyodrębnić. Zamiast używać handler, przejdę do argumentu branches. Jest to podobne do obsługi, ale ma się dostęp do pełnego węzła, a nie tylko do elementu. Chodzi o to, aby napisać zamknięcie, które ma miejsce do przechowywania danych, które gromadzimy, i funkcję przetwarzania każdej gałęzi dokumentu XML, który nas interesuje. Zacznijmy od zdefiniowania zamknięcia - dla naszych celów, funkcji, która zwraca listę funkcji

ourBranches <- function() { 

Musimy miejsce do przechowywania wyników możemy gromadzić, wybierając środowisko tak, że czasy wsuwane są stałe (nie na listę, którą będziemy musieli dołączyć do i byłoby pamięć nieefektywne)

store <- new.env() 

Analizator składni spodziewa się, że lista funkcji zostanie wywołana po wykryciu pasującego znacznika. Interesuje nas tag record. Funkcja, którą piszemy, otrzyma węzeł dokumentu XML. Chcemy wyodrębnić element id, którego użyjemy do przechowywania wartości (tekstu) w węźle. Dodajemy je do naszego sklepu.

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

Gdy dokument jest przetwarzany, chcielibyśmy wygodny sposób pobierać nasze wyniki, więc dodać funkcję do naszych własnych celów, niezależnie od węzłów w dokumencie

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

a następnie zakończyć zamknięcie wracając listę funkcji

list(record=record, getStore=getStore) 
} 

trudne pojęcie o to, że środowisko, w którym funkcja jest definiowana jest częścią funkcji, więc za każdym razem mówimy ourBranches() otrzymujemy listę funkcji i nowe środowisko, aby zachować nasze wyniki. Aby użyć, wywołaj plik xmlEventParse z pustym zestawem modułów obsługi zdarzeń i uzyskaj dostęp do naszego zgromadzonego sklepu.

> 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

dla innych, którzy mogą próbować Lear z M.Morgan - Oto kompletny kod

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

Sposób gałęzie nie zachowuje kolejność wydarzeń. Innymi słowy, kolejność "rekordu" w oddziałach $ getStore() sklepów różni się od tego w oryginalnym pliku xml. Z drugiej strony metody obsługi mogą zachować kolejność.Oto kod:

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" 

Inną korzyścią z używania modułów obsługi jest możliwość przechwytywania struktury hierarchicznej. Innymi słowy, możliwe jest uratowanie także przodków. Jednym z kluczowych punktów tego procesu jest użycie zmiennych globalnych, które można przypisać "< < -" zamiast "< -".

Powiązane problemy