R-从XML提取数据,然后传递到data.frame(使用NA丢失)



我有一个我想从中提取数据的XML文件。到目前为止

样本XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:ArchiveView>
    <Notification ID="1001">
        <persons>
            <Timestamp>07:39:25</Timestamp>
            <person type="A" name="Barney">
                <uniqueUserId>2222</uniqueUserId>
            </person>
        </persons>
        <persons>
            <Timestamp>08:40:25</Timestamp>
            <person type="B" name="John">
                <uniqueUserId>1111</uniqueUserId>
            </person>
        </persons>
    </Notification>
    <Notification ID="1002">
        <persons>
            <Timestamp>14:39:25</Timestamp>
            <person type="A" name="Barney">
                <uniqueUserId>2222</uniqueUserId>
            </person>
        </persons>
    </Notification>
    <Notification ID="1003">
    </Notification>
</ns2:ArchiveView>

由于可以分配给通知的最大人数为3,所以我想获得一个数据。形式看起来像这样:

ID    name1    time1     type1    name2    time2     type2    name3    time3     type3
1001  Barney   07:39:25  A        John     08:40:25  B        NA       NA        NA
1002  Barney   14:39:25  A        NA       NA        NA       NA       NA        NA
1003  NA       NA        NA       NA       NA        NA       NA       NA        NA       

我设法到目前为止得到了什么:

doc <- read_xml( "./data/test.xml" )

提取所有ID

df.ID <- data.frame( 
           ID = xml_find_all( doc, ".//Notifications" ) %>% xml_attrs() %>%  unlist() , 
           stringsAsFactors = FALSE )

确定已附加人员的通知ID

ID.with.persons <- xml_find_all( doc, ".//Notifications[ persons ]" ) %>% 
                   xml_attrs() %>% 
                   unlist()

与附加人员的通知创建一个节点

nodes.persons <- xml_find_all( doc, ".//Notifications[ persons ]" 

我还设法获得了所有人的名字(一个向量(

persons.name <- nodes.persons %>% xml_attr("name") %>% unlist()

我感觉自己非常接近解决方案,但是我不能围绕如何将所有这些数据合并到一个不错的数据中(如上所述(。

所有建议都受到热烈的赞赏:(

这是一种非常有效的方法(我对R很新,所以它可能不是很r的。将其转换为末端的矩阵,然后将其插入数据框架中。这之所以起作用,是因为有固定数量的列可以用。

构建矩阵。
library(xml2)
doc <- read_xml("test.xml")
row <- c()
notifications <- xml_find_all(doc, ".//Notification")
for (i in 1:length(notifications)) {
    row <- c(row, xml_attr(notifications[i], "ID"))
    for (j in 1:3) {
        person <- xml_find_all(notifications[i], sprintf("persons[%d]", j))
        if (length(person) > 0) {
            row <- c(row, xml_find_chr(person, "string(./person/@name)"))
            row <- c(row, xml_find_chr(person, "string(./Timestamp/text())"))
            row <- c(row, xml_find_chr(person, "string(./person/@type)"))
        } else {
            row <- c(row, NA, NA, NA)
        }
    }
}
df <- data.frame(matrix(data=rows, ncol=10, byrow=TRUE))
colnames(df) <- c("ID", "name1", "time1", "type1", "name2", "time2", "type2", "name3", "time3", "type3")
df

输出:

    ID  name1    time1 type1 name2    time2 type2 name3 time3 type3
1 1001 Barney 07:39:25     A  John 08:40:25     B  <NA>  <NA>  <NA>
2 1002 Barney 14:39:25     A  <NA>     <NA>  <NA>  <NA>  <NA>  <NA>
3 1003   <NA>     <NA>  <NA>  <NA>     <NA>  <NA>  <NA>  <NA>  <NA>

这是解决方案。它的手动编码比我想要的更多,但确实显示了解决方案技术:

library(xml2)
doc<-read_xml("*Your xml Document goes here*")
#find the Notification nodes
Notices<-xml_find_all( doc, ".//Notification" )
#find all of the timestamps in each Notification
timestamps<-sapply(Notices, function(x){xml_text(xml_find_all(x, ".//Timestamp"))})
#extract the three timestamps in each Notification (missing ones return NA)
#sapply returns a column, need to transpose to create the row in the data frame
time.df<-data.frame(t(sapply(timestamps, function(x){c(x[1], x[2], x[3])})))
#rename the column names
names(time.df)<-paste0("time", 1:3)
#repeat for the person's name and type
persons.name <-sapply(Notices, function(x){x %>% xml_find_all(  ".//person" ) %>% xml_attr("name")})
name.df<-data.frame(t(sapply(persons.name, function(x){c(x[1], x[2], x[3])})))
names(name.df)<-paste0("name", 1:3)
persons.type <-sapply(Notices, function(x){x %>% xml_find_all(  ".//person" ) %>% xml_attr("type")})
type.df<-data.frame(t(sapply(persons.type, function(x){c(x[1], x[2], x[3])})))
names(type.df)<-paste0("type", 1:3)
#assemble the final answer and rearrange the column order
answer<-cbind(name.df, time.df, type.df)
answer<-answer[,c(1, 4, 7, 2, 5, 8, 3, 6, 9)]
df.ID <- data.frame(ID = xml_find_all( doc, ".//Notification" ) %>%  
        xml_attr("ID"), stringsAsFactors = FALSE)
answer<-cbind(df.ID, answer)

代码的评论说明了解决方案所采取的步骤。我确定可能有一些优化,但这是一个很好的开始。

相关内容

  • 没有找到相关文章

最新更新