2 votes

Identifier les attributs uniques d'un fichier xml

J'ai besoin d'identifier tous les attributs uniques d'un fichier xml pour transformer correctement le xml en un cadre de données.

Le R-script suivant permet d'effectuer la transformation. Mais seulement, si les attributs sont connus.

library(rvest)
library(magrittr)
xml <- read_xml('<?xml version="1.0" encoding="UTF-8"?>
            <movies>
              <movie Id="1" Name="Movie 1" IMDB="8,4" Date="2008-07-31T00:00:00.000" Views="649" />
              <movie Id="2" Name="Movie 2" IMDB="3,7" Location="El Cerrito, CA" Actor="Tom Hanks" />
            </movies>')

movies <- xml %>% xml_nodes("movie")
data.frame(
  Id = movies %>% xml_attr("Id"),
  Name = movies %>% xml_attr("Name"),
  IMDB = movies %>% xml_attr("IMDB"),
  Date = movies %>% xml_attr("Date"),
  Views = movies %>% xml_attr("Views"),
  Location = movies %>% xml_attr("Location"), 
  Actor = movies %>% xml_attr("Actor")
)  

La sortie ressemblera à ceci :

  Id    Name IMDB                    Date Views       Location     Actor
1  1 Movie 1  8,4 2008-07-31T00:00:00.000   649           <NA>      <NA>
2  2 Movie 2  3,7                    <NA>  <NA> El Cerrito, CA Tom Hanks

Comment est-il possible d'obtenir une liste de tous les attributs uniques (les données actuelles sont trop longues pour les vérifier manuellement) ?

Pour cet exemple, le résultat souhaité devrait ressembler à la liste suivante :

[1] "Id"
[2] "Name"
[3] "IMDB"
[4] "Date"
[5] "Views"
[6] "Location"
[7] "Actor"

2voto

G5W Points 20163

Utilisation de vos données :

Sample = '<?xml version="1.0" encoding="UTF-8"?>
            <movies>
              <movie Id="1" Name="Movie 1" IMDB="8,4" Date="2008-07-31T00:00:00.000" Views="649" />
              <movie Id="2" Name="Movie 2" IMDB="3,7" Location="El Cerrito, CA" Actor="Tom Hanks" />
            </movies>'

Vous pouvez obtenir la plupart de ce que vous voulez de str_extract_all dans le stringr et une expression régulière. Du moins tel que je l'ai fait, vous devez nettoyer les signes = parasites et ensuite utiliser unique pour se débarrasser des doublons.

unique(sub("=", "", str_extract_all(Sample, "\\w+=")[[1]]))
[1] "version"  "encoding" "Id"       "Name"     "IMDB"     "Date"     "Views"   
[8] "Location" "Actor"

Si vous Ne le fais pas. Si vous souhaitez inclure la balise "encodage" de l'en-tête, vous pouvez exécuter la commande suivante

Sample = sub(".*(<movies.*?</movies>).*", "\\1", Sample)

d'abord pour ne sélectionner que la partie contenant les films.

1voto

Dave2e Points 5768

Voici une approche générale utilisant le paquet xml2 (il est chargé avec rvest). Elle fonctionne et est un peu verbeuse (pour fournir un guide pas à pas), mais je n'ai pas eu le temps de l'optimiser. Voir les commentaires du code pour une explication de son fonctionnement.

library(xml2)
library(dplyr)

xml <- read_xml('<?xml version="1.0" encoding="UTF-8"?>
                <movies>
                <movie Id="1" Name="Movie 1" IMDB="8,4" Date="2008-07-31T00:00:00.000" Views="649" />
                <movie Id="2" Name="Movie 2" IMDB="3,7" Location="El Cerrito, CA" Actor="Tom Hanks" />
                </movies>')

#find all the movie nodes, returns a list of vectors
movies <- xml %>% xml_find_all("movie")   

#get all of the attributes and their values
attrs<-xml_attrs(movies)

#convert the lists into rows and merge the rows
# finally convert to a data frame
# based on recommendation from jstuhh
finalanswer<-bind_rows(lapply(attrs, as.list))

1voto

jwarz Points 107

En utilisant la solution de G5W, le code complet pour créer les cadres de données (j'ai seulement dû ajuster la sous-fonction pour éviter d'extraire les informations html) :

library(XML)
library(rvest)
library(magrittr)
library(stringr)

# 1. Read xml to "xml_document" / "xml_node"
data_xml <- read_xml('<?xml version="1.0" encoding="UTF-8"?>
                <movies>
                     <movie Id="1" Name="Movie 1" IMDB="8,4" Date="2008-07-31T00:00:00.000" Views="649" />
                     <movie Id="2" Name="Movie 2" IMDB="3,7" Location="El Cerrito, CA" Actor="Tom Hanks" />
                     </movies>')

# 2. Transform data to a string
data_char_all <- as.character(data_xml)

# 3. Remove 'encoding' and 'version' tag from the header
data_char_movies = sub(".*(<movies.*?</movies>).*", "\\1", data_char_all)

# 4. Extract all unique attributes
attr <- unique(sub("=\"", "", str_extract_all(data_char_movies, "\\w+=\"")[[1]]))

# 5. Create dataframe
# 5.1 Create xml_nodeset and assign all nodes
movies <- data_xml %>% xml_nodes("movie")

# 5.2 Create empty dataframe and assign values

df <- setNames(data.frame(matrix(ncol = length(attr), nrow = length(movies))), attr)

for (i in 1:length(attr)) {

  df[i] <- movies %>% xml_attr(attr[i])

# 6. Print result
df

  Id    Name IMDB                    Date Views       Location     Actor
1  1 Movie 1  8,4 2008-07-31T00:00:00.000   649           <NA>      <NA>
2  2 Movie 2  3,7                    <NA>  <NA> El Cerrito, CA Tom Hanks

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X