我有一个由 Windows 日志生成的大 xml 文件,我需要将其导入 R 中以分析记录的事件之间的一些相关性。 我遇到的问题是事件的详细信息 (EventData) 保留为 xml 的属性,并且属性的数量根据事件的类型而变化。
要导入的简化 xml 是:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Events>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<EventID>259</EventID>
<Version>0</Version>
<Level>2</Level>
<TimeCreated SystemTime="2024-07-10T15:02:35.203376200Z"/>
</System>
<EventData>
<Data Name="TCP">0</Data>
<Data Name="InterfaceIP">0.0.0.0</Data>
<Data Name="Source">192.168.109.4</Data>
<Data Name="QNAME"/>
</EventData>
</Event>
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<EventID>256</EventID>
<Version>0</Version>
<Level>4</Level>
<TimeCreated SystemTime="2024-07-10T15:02:35.203362300Z"/>
</System>
<EventData>
<Data Name="TCP">0</Data>
<Data Name="InterfaceIP">0.0.0.0</Data>
<Data Name="Source">192.168.109.4</Data>
<Data Name="QNAME">microsoft.com.</Data>
<Data Name="QTYPE">0</Data>
<Data Name="XID">22342</Data>
<Data Name="Port">65220</Data>
<Data Name="Flags">16979</Data>
<Data Name="BufferSize">108</Data>
</EventData>
</Event>
</Events>
这正是我所期望的。
我写的代码是:
library(xml2)
library(tibble)
library(dplyr)
file_dns <- c("./test_ridotto_2.xml")
read_xml(file_dns) -> dns
dns_items <- tibble(
event_id = xml_find_all(x = dns, xpath = "/Events/Event/System/EventID") |> xml_text(),
time_created = xml_find_all(x = dns, xpath = "/Events/Event/System/TimeCreated") |> xml_attr(attr = "SystemTime"),
info4 = xml_find_all(x = dns, xpath = "/Events/Event/EventData") |> as_list()
)
我遇到的问题是,我不明白如何继续拆分列并为它们指定属性的名称,因为属性的数量和列的数量逐行变化,并取决于属性的类型已记录事件。 我尝试了 unnest_wider 命令,但它丢失了属性,并且在我的简化测试文件上看起来很慢。 制作文件为1Gb。
怎样才能得到预期的结果?
谢谢 多梅尼科
此脚本从每个事件中提取 eventID 和创建时间,然后循环访问事件并提取数据元素和节点 ID 来为最终答案创建数据帧。
请参阅下面的评论了解步骤。
library(xml2)
library(dplyr)
#read page and strip namespace
page <- read_xml(text)
xml_ns(page)
#find the events nodes
events <- xml_find_all(page, ".//Event")
#get the eventID and Created time
eventID <- xml_find_first(events, ".//EventID") %>% xml_text()
CreatedTime <-xml_find_first(events, ".//TimeCreated") %>% xml_attr("SystemTime")
#loop through the events and extract the data
#make a data frame and create the proper column headings
dfs <- lapply(events, function(node){
data <- xml_find_all(node, ".//Data") %>% xml_text()
tag <- xml_find_all(node, ".//Data") %>% xml_attrs() %>% unlist()
names(tag)<-NULL
df<-as.data.frame(t(data))
names(df) <- tag
df
})
#make a data frame for the answer
answer <- bind_rows(dfs)
#add the event ID and timecreated
answer <-bind_cols(EventID=eventID, CreatedTime=CreatedTime, answer)
EventID CreatedTime TCP InterfaceIP Source QNAME QTYPE XID Port Flags BufferSize
1 259 2024-07-10T15:02:35.203376200Z 0 0.0.0.0 192.168.109.4 <NA> <NA> <NA> <NA> <NA>
2 256 2024-07-10T15:02:35.203362300Z 0 0.0.0.0 192.168.109.4 microsoft.com. 0 22342 65220 16979 108