【问题标题】:Values assigned to incorrect node when converting xml to data frame将 xml 转换为数据框时分配给错误节点的值
【发布时间】:2017-06-12 06:52:30
【问题描述】:

我有数以万计的 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 文件和下面的脚本,我的数据框包含一个名为“meta”的列,其值为 uuid:ff93ead6-77b3-4c14-be7c-cbeb520ce0d7。但是,我期待/希望它包含一个名为“instanceID”的列,该列具有相同的值,因为后者标记立即围绕该值。这通常发生在其他嵌套节点上。有人有什么建议吗?

# 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)

【问题讨论】:

  • as.data.frame(as.list(unlist(temp_list, recursive = TRUE)), stringsAsFactors = FALSE)(在您未修改的temp_list上)这样做吗?小不便:一切都转换为字符,名称以父节点名称为前缀,例如"meta.instanceID "你想要"instanceID"
  • 适用于玩具数据集,稍后在完整数据上进行测试。愿意解释为什么这与我的代码相比有效吗?不便之处很好(在 colnames 中没有 petiods '.' 并且可以保留带有子字符串的子字符串。

标签: r xml list nested-lists


【解决方案1】:

temp_list &lt;- "dat.xml" %&gt;% XML::xmlParse() %&gt;% 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

unlistrecursive = TRUE 将整个列表展平为一个向量(一个具有数字隐式转换的字符向量 (编辑:刚刚注意到一切都已经是字符了,xmlParse 没有做任何自动类归属),所以如果您需要integerdouble),请小心转换回来。默认的use.names = TRUE 将嵌套列表中的名称与一个点连接起来,为您提供诸如id_consent.consentmeta.instanceID 之类的名称。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 2019-04-26
    相关资源
    最近更新 更多