Разобрать xml в dataframe, включая потомки и атрибуты в R - PullRequest
1 голос
/ 14 октября 2019

Я пытаюсь создать фрейм данных из прикрепленного xml https://1drv.ms/u/s!Am7buNMZi-gwgeBmbk6A-NRIRarjYw?e=Pcgm7c

Мне нужно получить для всех игроков информацию о столбцах и информацию о команде (родительской)

Пример XML

<SoccerFeed timestamp="20190519T183022+0000">
  <SoccerDocument Type="SQUADS Latest" competition_code="ES_PL" competition_id="23" competition_name="Spanish La Liga" season_id="2018" season_name="Season 2018/2019">
    <Team country="Spain" country_id="4" country_iso="ES" official_club_name="Deportivo Alavés S.A.D." region_id="17" region_name="Europe" short_club_name="Alavés" uID="t173">
      <Founded>1921</Founded>
      <Name>Alavés</Name>
      <Player uID="p91406">
        <Name>Fernando Pacheco</Name>
        <Position>Goalkeeper</Position>
        <Stat Type="first_name">Fernando</Stat>
        <Stat Type="last_name">Pacheco</Stat>
        <Stat Type="birth_date">1992-05-18</Stat>
        <Stat Type="birth_place">Badajoz</Stat>
        <Stat Type="first_nationality">Spain</Stat>
        <Stat Type="preferred_foot">Left</Stat>
        <Stat Type="weight">81</Stat>
        <Stat Type="height">186</Stat>
        <Stat Type="jersey_num">1</Stat>
        <Stat Type="real_position">Goalkeeper</Stat>
        <Stat Type="real_position_side">Unknown</Stat>
        <Stat Type="join_date">2015-08-07</Stat>
        <Stat Type="country">Spain</Stat>
      </Player>
      <Player uID="p176245">
        <Name>Antonio Sivera</Name>
        <Position>Goalkeeper</Position>
        <Stat Type="first_name">Antonio</Stat>
        <Stat Type="last_name">Sivera</Stat>
        <Stat Type="birth_date">1996-08-11</Stat>
        <Stat Type="birth_place">Jávea</Stat>
        <Stat Type="first_nationality">Spain</Stat>
        <Stat Type="preferred_foot">Right</Stat>
        <Stat Type="weight">75</Stat>
        <Stat Type="height">184</Stat>
        <Stat Type="jersey_num">13</Stat>
        <Stat Type="real_position">Goalkeeper</Stat>
        <Stat Type="real_position_side">Unknown</Stat>
        <Stat Type="join_date">2017-07-19</Stat>
        <Stat Type="country">Spain</Stat>
      </Player>
     </Team>
     <Team city="Madrid" country="Spain" country_id="4" country_iso="ES" official_club_name="Club Atlético de Madrid S.A.D" postal_code="28005" region_id="17" region_name="Europe" short_club_name="Atlético" street="Paseo Virgen del Puerto, 67" uID="t175" web_address="www.clubatleticodemadrid.com/">
      <Founded>1903</Founded>
      <Name>Atlético de Madrid</Name>
      <Player uID="p59981">
        <Name>Antonio Adán</Name>
        <Position>Goalkeeper</Position>
        <Stat Type="first_name">Antonio</Stat>
        <Stat Type="last_name">Adán</Stat>
        <Stat Type="birth_date">1987-05-13</Stat>
        <Stat Type="birth_place">Madrid</Stat>
        <Stat Type="first_nationality">Spain</Stat>
        <Stat Type="preferred_foot">Left</Stat>
        <Stat Type="weight">92</Stat>
        <Stat Type="height">190</Stat>
        <Stat Type="jersey_num">1</Stat>
        <Stat Type="real_position">Goalkeeper</Stat>
        <Stat Type="real_position_side">Unknown</Stat>
        <Stat Type="join_date">2018-07-10</Stat>
        <Stat Type="country">Spain</Stat>
      </Player>
      <Player uID="p81352">
        <Name>Jan Oblak</Name>
        <Position>Goalkeeper</Position>
        <Stat Type="first_name">Jan</Stat>
        <Stat Type="last_name">Oblak</Stat>
        <Stat Type="birth_date">1993-01-07</Stat>
        <Stat Type="birth_place">Skojfa Loka</Stat>
        <Stat Type="first_nationality">Slovenia</Stat>
        <Stat Type="preferred_foot">Right</Stat>
        <Stat Type="weight">87</Stat>
        <Stat Type="height">188</Stat>
        <Stat Type="jersey_num">13</Stat>
        <Stat Type="real_position">Goalkeeper</Stat>
        <Stat Type="real_position_side">Unknown</Stat>
        <Stat Type="join_date">2014-07-16</Stat>
        <Stat Type="country">Slovenia</Stat>
      </Player>
     </Team>
   </SoccerDocument>
</SoccerFeed>



Мои нужные столбцы

КОЛОННЫ КОМАНДЫ

  • страна (атрибут SoccerFeed / SoccerDocument / Team)
  • country_id (атрибут SoccerFeed / SoccerDocument / Team)
  • country_iso (атрибут SoccerFeed / SoccerDocument / Team)
  • official_club_name (атрибут SoccerFeed / SoccerDocument / Team)
  • region_id (атрибут SoccerFeed / SoccerDocument / Team)
  • region_name (SoccerFeed / SoccerDocument / атрибут команды)
  • short_club_name (SoccerFeed / SoccerDocument / атрибут команды)
  • team_uID (SoccerFeed / SoccerDocument / атрибут команды UID)
  • имя_команды (SoccerFeed/ SoccerDocument / Team / Name)
  • team_found (SoccerFeed / SoccerDocument / Team / Founded)

столбцы ИГРОКА

  • player_uID (/ SoccerFeed/ SoccerDocument / Team / Player)

  • player_name (/ SoccerFeed / SoccerDocument / Team / Player / Name)

  • player_position (/ SoccerFeed / SoccerDocument /Команда / Игрок / Позиция)

  • player_first_name (/ SoccerFeed / SoccerDocument / Team / Player / Stat типа = имя)
  • player_last_name (/ SoccerFeed / SoccerDocument / Team / Player / Statтип = фамилия)
  • player_first_name (/ SoccerFeed / SoccerDocument / Team / Player / тип статистики = имя)
  • player_birth_place (/ SoccerFeed / SoccerDocument / Team / Player / Stat тип = место рождения)
  • player_preferred_foot (/ SoccerFeed / SoccerDocument / Team / Player / Тип стата = предпочитаемый_фут) ... статистика других игроков (вес, рост, трикотажное число, ... страна)

Меня не интересуют команды и узлы игрока в разделе «Изменения игрока» ниже раздела / SoccerFeed / SoccerDocument / PlayerChanges

Я начал с tidyverse и xml2, чтобы собрать информацию об игроке в сочетании с tidyverse, но я не смогle, чтобы получить информацию о родителях команды и другую статистику для игроков


library(xml2)
library(tidyverse)
library(plyr)



x <- read_xml("squads.xml")

players <- x %>% 
  xml_find_all('/SoccerFeed/SoccerDocument/Team/Player') %>% 
  map_df(~flatten(c(xml_attrs(.x), 
                    map(xml_children(.x), 
                        ~set_names(as.list(xml_text(.x)), xml_name(.x)))))) %>%
  type_convert()

1 Ответ

1 голос
/ 14 октября 2019

Поскольку вы используете xml2 и вам требуются различные узлы данных, которые различаются по вложенным уровням, рассмотрим XSLT , язык специального назначения (например, SQL), предназначенный для преобразования файлов XML. В R пакет xslt, родственный модулю xml2, может запускать сценарии XSLT 1.0. Рекурсивная шаблонная природа XSLT помогает избежать сложных вложенных циклов или отображений на уровне приложений, в данном случае R. Плюс XSLT является переносимым (например, SQL) и может быть запущен вне R.

Хотя это может быть целоеНовая концепция, выходящая из левого поля, требующая обучения, позволяет сглаживать ваш XML в соответствии с двумерной структурой, необходимой для наборов данных. Вы также отделяете обработку XML (XSLT) от обработки данных (R). В частности, поддерживается только уровень Player с соответствующими данными Team , перенесенными вниз (см. Демонстрацию).

XSLT (сохранить как. xsl, специальный XML-файл)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/SoccerFeed|SoccerDocument">
      <xsl:apply-templates select="*"/>
  </xsl:template>

  <xsl:template match="Team">
      <xsl:apply-templates select="Player"/>
  </xsl:template>

  <xsl:template match="Team/@*">
    <xsl:element name="{concat('team_', name(.))}">
      <xsl:value-of select="."/>      
    </xsl:element>
  </xsl:template>

  <xsl:template match="Player">
    <xsl:copy>
      <xsl:apply-templates select="ancestor::Team/@*"/>
      <xsl:copy-of select="Name|Position"/>
      <xsl:apply-templates select="@*|Stat"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Player/@*">
    <xsl:element name="{name(.)}">
      <xsl:value-of select="."/>      
    </xsl:element>
  </xsl:template>

  <xsl:template match="Stat">
    <xsl:element name="{@Type}">
      <xsl:value-of select="text()"/>     
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Онлайн-демонстрация

R (приводит к кадру данныхвсе типы символов)

library(xml2)
library(xslt)
library(dplyr)

# INPUT SOURCE
doc <- read_xml("/path/to/Input.xml")
style <- read_xml("/path/to/Style.xsl", package = "xslt")

# TRANSFORM 
new_xml <- xml_xslt(doc, style)

# RETRIEVE Player NODES
recs <- xml_find_all(new_xml, "//Player")

# BIND EACH CHILD TEXT AND NAME TO Player DFs
df_list <- lapply(recs, function(r) 
    data.frame(rbind(setNames(xml_text(xml_children(r)), 
                              xml_name(xml_children(r)))),
               stringsAsFactors = FALSE)
)

# BIND ALL DFs TO SINGLE MASTER DF
final_df <- bind_rows(df_list)
...