将xml转换为数据框时分配给错误节点的值

时间:2017-06-12 06:52:31

标签: r xml list nested-lists

我正在尝试将数万个XML文件转换为R数据帧。每个XML文件可能有不同的节点,每个节点的不同值,不同的结构等等。所以我试图以一种不要求明确地键入每个单独文件的结构的方式来做这件事。但是,我无法将值分配给正确的标签。

假设我在名为" dat.xml"的文件中包含以下XML:

<?xml version="1.0" encoding="UTF-8"?>
<HH_V2 id="HH_V2">
    <start>2017-01-30T11:31:56.811Z</start>
    <end>2017-01-30T12:08:19.489Z</end>
    <today>2017-01-30</today>
    <deviceid>351569060022943</deviceid>
    <time_st>2017-01-30</time_st>
    <int_name>21</int_name>
    <superv>4</superv>
    <region>2</region>
    <new_ea_flag>0</new_ea_flag>
    <unique_id>c3d5c37d-b5c6-4b9d-a922-3b4f5be0e5ac</unique_id>
    <village>Boana</village>
    <hh_serial>71710003101</hh_serial>
    <hh_serial2>71710003101</hh_serial2>
    <id_consent>
        <iconsent>
            <iconsentlong />
        </iconsent>
        <consent>1</consent>
    </id_consent>
        <meta>
        <instanceID>uuid:ff93ead6-77b3-4c14-be7c-cbeb520ce0d7</instanceID>
    </meta>
</HH_V2>

使用上面的xml文件和下面的脚本,我的数据框包含一个名为&#34; meta&#34;的列。值为uuid:ff93ead6-77b3-4c14-be7c-cbeb520ce0d7。但是,我期待/希望它包含一个名为&#34; instanceID&#34;的列。基于后一个标签立即围绕该值的事实,具有相同的值。这通常发生在其他嵌套节点上。有没有人有任何建议?

# Load packages
library(dplyr)
library(XML)

# Convert xml file to list of lists
temp_list <- "dat.xml" %>% XML::xmlParse() %>% XML::xmlToList()

# Unlist and store content as a single column with row
# names for each variable in that node and the value of
#  the variable in a single column.
for (j in 1:length(temp_list)) {
  temp_list[[j]] <- temp_list[[j]] %>% unlist(recursive = TRUE) %>% 
  as.data.frame(stringsAsFactors = FALSE)
  }

# Each file is now a list of data frames comprised of 
# 1 column of values and row names for each variable. So
# we bind these in order of their appearance in the list
# of data frames
temp_list <- do.call(rbind, temp_list)

# Since we want each row to be a column and each column
# to be a variable ('wide' format), we transpose the
# dataframe to produce a single row for each instance
# of the submitted form
t(temp_list) %>% as.data.frame(stringsAsFactors = FALSE)

1 个答案:

答案 0 :(得分:0)

temp_list <- "dat.xml" %>% XML::xmlParse() %>% XML::xmlToList()之后我建议使用更简单的代码:

as.data.frame(as.list(unlist(temp_list, recursive = TRUE)), stringsAsFactors = FALSE)

#                      start                      end      today        deviceid    time_st int_name superv region new_ea_flag                            unique_id village   hh_serial  hh_serial2 id_consent.consent                           meta.instanceID .attrs.id
# 1 2017-01-30T11:31:56.811Z 2017-01-30T12:08:19.489Z 2017-01-30 351569060022943 2017-01-30       21      4      2           0 c3d5c37d-b5c6-4b9d-a922-3b4f5be0e5ac   Boana 71710003101 71710003101                  1 uuid:ff93ead6-77b3-4c14-be7c-cbeb520ce0d7     HH_V2
带有unlist

recursive = TRUE将整个列表展平为一个向量(带有数字隐式转换的字符向量(编辑:只是注意到所有内容都已经是字符,xmlParse没有做任何自动类归属),因此如果您需要integerdouble,请小心转换回来。默认use.names = TRUE在嵌套列表中使用点连接名称,为您提供id_consent.consentmeta.instanceID等名称。

然后as.data.frame(as.list())使其成为一行数据框。

与您的代码的区别在于:for循环用1个观察x 1变量的单个数据帧替换每个父节点,没有rownames,因此丢失嵌套名称,仅保留父节点的最“外部”名称。然后rbind将它们堆叠在一起,这些名称在结果数据框中用作rownames。 t()将其转换回字符矩阵! (现在名称用作名字)。最后,as.data.frame再次将其转回数据框。这是很多不必要的步骤。我的解决方案也可能有一些(unlist()然后as.list() ;-) ...但稍微少一些; - )