当信息同时在属性和文本节点中时,将嵌套的XML文档转换为数据框

时间:2019-03-11 16:08:01

标签: r xml dataframe

背景

我有一个具有以下结构的XML文档:

<records>
 <record id="512" size="1">
  <user id="8412" origin="ab"/>
  <category id="105">Certificates</category>
  <rating>80</rating>
  <text>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
  </text>
 </record>
 <record id="452" size="2">
  <user id="7623" origin="bb"/>
  <category id="105">Certificates</category>
  <rating>70</rating>
  <text>
  Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
  </text>
 </record>
</records>

我要做什么:

使用R,我试图将XML信息转换为数据框,其中每一行代表一个记录,每一列代表该记录的属性或文本数据(目的是包括存在的所有数据)在XML文档中。)

这是最终输出应如下所示:

Record ID | Size | User ID | ... | Text           |
       452|     2|     7623| ... | Lorem ipsum... | 

此外,由于大约有1,000,000条记录,并且包含这些记录的文件约为500MB,因此我试图找到一种相对有效的方法。

到目前为止,我已经尝试过:

我已经查看了与该主题相关的许多问题,但是没有一个提供了适用于这种情况的解决方案。

首先,我尝试使用以下代码在XML包中使用'xmlToDataFrame'函数,但它仅提取文本数据,而不提取属性:

library(XML)
doc = xmlParse("My_document.xml")
xmldf = xmlToDataFrame(doc, nodes = "//record")
xmldf = xmlToDataFrame(nodes = getNodeSet(doc, "//record"))

尽管我尝试在最初导入XML文档的过程中确实提取了相关的属性数据,但是当我尝试使用flatxml包时,也会发生同样的情况:

library(flatxml)
doc = fxml_importXMLFlat("My_document.xml")
xmldf = fxml_toDataFrame(xml_original, siblings.of = 2)

我还尝试了使用xml2包的稍微不同的方法:

library(xml2)
doc <- read_xml('My_document.xml')
rows <- xml_children(doc)
data.frame(
  Record_ID = as.numeric(xml_attr(rows,"id")),
  Size = as.numeric(xml_attr(rows,"size")),
  User_ID = as.numeric(xml_attr(rows,"id")),
  Origin = as.character(xml_attr(rows,"origin")),
  Category = as.character(xml_text(rows,"category")),
  Category_ID = as.numeric(xml_attr(rows,"id")),
  Rating = as.numeric(xml_text(rows,"rating")),
  Text = as.character(xml_text(rows,"text"))
) -> xmldf

在这里,我遇到了一系列不同的问题:我能够提取属性数据,但只能从“记录”节点中提取。这意味着它将复制“ User_ID”记录中的“ id”数据,并且无法访问诸如“ origin”属性之类的相关数据。此外,每次我尝试提取文本信息时,此过程还将同时从所有节点提取所有文本信息。

1 个答案:

答案 0 :(得分:1)

假设每个记录 user 和同级标记,请考虑使用内部方法xmlAttrsToDataFrame和元素xmlToDataFrame绑定属性。 >。

library(XML)
...

# BIND ATTRIBUTES AND ELEMENTS
record_df <- cbind(XML:::xmlAttrsToDataFrame(getNodeSet(doc, path='//record')),
                   XML:::xmlAttrsToDataFrame(getNodeSet(doc, path='//user')),
                   xmlToDataFrame(doc, nodes = getNodeSet(doc, "//record"))
             )    

# RENAME COLUMNS
record_df <- setNames(record_df, c("record_id", "record_size", "user_id", "user_origin",
                                   "record_user", "record_category", "record_rating", "record_text"))

record_df
#   record_id record_size user_id user_origin record_user record_category record_rating              record_text
# 1       512           1    8412          ab                Certificates            80  \nLorem ipsum dolor ...
# 2       452           2    7623          bb                Certificates            70   \nUt enim ad minim ...