You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R中for循环未完整处理XML脚本 解析系统日志仅捕获首条事件

问题描述

我正在编写解析系统日志类XML文件的例程,用于捕获登录与注销消息。我设置了多处检查点验证XML文件是否被完整读取,但打印dataframe时,仅能捕获到第一条事件。

原有代码如下:

LG.df <- read_xml("Syslog.xml")


xml_ns(LG.df)
NS<- xml_children(xml_children(LG.df))


EV<- ""
DT<- ""
AN<- ""
AD<- ""
WSN<- ""
SA<- ""

LogEvents.df<- data.frame(EV, DT, AN, AD, WSN, SA)

print(LG.df)


for (i in sequence(length(NS))) {


DT<- NS[1]
DT<- gsub("<DateTime>","",as.character(DT))
DT<- gsub("</DateTime>","",as.character(DT))
#print(DT)
Pr<- NS[2]
Pr<- gsub("<Priority>","",as.character(Pr))
Pr<- gsub("</Priority>","",as.character(Pr))
#print(Pr)
SH<- NS[3]
SH<- gsub("<Source_Host>","",as.character(SH))
SH<- gsub("</Source_Host>","",as.character(SH))
#print(SH)
MT<- NS[4]
MT<- gsub("<MessageText>","",as.character(MT))
MT<- gsub("</MessageText>","",as.character(MT))
#print(MT)


EV<- str_match(MT, "\\d{4}(?=\\tMicrosoft-Windows-Security-Auditing)")

#print(EV)

AN<- str_match(MT, "(?<=Account Name:\\t\\t).*?(?=\\n)")
SID<- str_match(MT, "(?<=Security ID:\\t\\t).*?(?=\\n)")
AD<- str_match(MT, "(?<=Account Domain:\\t\\t).*?(?=\\n)")
WSN<- str_match(MT, "(?<=Workstation Name:\\t\\t).*?(?=\\n)")
SA<- str_match(MT, "(?<=Source Network Address:\\t\\t).*?(?=\\n)")




if(EV == 4624){(LogEvents.df$EV <-(EV))
  (LogEvents.df$DT<- (DT))
  (LogEvents.df$AN<- (AN))
  (LogEvents.df$AD<- (AD))
  (LogEvents.df$WSN<- (WSN))
  (LogEvents.df$SA<- (SA))


  } else if(EV == 4634){(LogEvents.df$EV <-( EV))}
  (LogEvents.df$DT<- (DT))
  (LogEvents.df$AN<- (AN))
  (LogEvents.df$AD<- (AD))
  (LogEvents.df$WSN<- (WSN))
  (LogEvents.df$SA<- (SA))



}
错误原因

代码存在4个核心问题,导致只能拿到单条数据:

  • 循环索引完全未生效:定义了迭代变量i,但所有节点取值都写死为NS[1]/NS[2]/NS[3]/NS[4],每次循环都在取固定位置的第一个事件节点,从未遍历所有节点。
  • 结果写入逻辑错误:初始创建的LogEvents.df只有1行,循环中每次都是直接给整列赋值覆盖旧值,从未追加新行,最终只会保留最后一次写入的单条数据。
  • 条件判断括号错位:else if(EV == 4634)分支后,其余字段的赋值被写在判断分支外,括号配对错误,非目标事件也会错误覆盖数据。
  • XML解析方式不规范:用gsub正则替换标签提取值的容错性极差,一旦文本内容包含特殊字符、标签格式有细微变化就会解析失败,应该使用xml2包自带的节点取值函数。
修正方案

修正后的可运行代码如下:

library(xml2)
library(stringr)

# 读取XML文件,若存在命名空间解析问题可加一行xml_ns_strip(LG)移除命名空间
LG <- read_xml("Syslog.xml")
# 替换XPath为你实际日志里的事件节点路径,这里默认是Event节点
all_events <- xml_find_all(LG, ".//Event")

# 初始化空结果表,不提前插入空行
LogEvents.df <- data.frame(
  EV = character(),
  DT = character(),
  AN = character(),
  AD = character(),
  WSN = character(),
  SA = character(),
  stringsAsFactors = FALSE
)

# 逐个遍历事件节点
for (event_node in all_events) {
  # 直接用xml_text提取节点文本,放弃gsub硬替换标签的写法
  DT <- xml_text(xml_find_first(event_node, "./DateTime"))
  MT <- xml_text(xml_find_first(event_node, "./MessageText"))
  
  # 提取事件ID,str_match返回矩阵,取[,1]拿到匹配结果
  EV <- str_match(MT, "\\d{4}(?=\\tMicrosoft-Windows-Security-Auditing)")[,1]
  # 非登录(4624)/注销(4634)事件直接跳过
  if (!EV %in% c("4624", "4634") | is.na(EV)) next
  
  # 提取其余字段
  AN <- str_match(MT, "(?<=Account Name:\\t\\t).*?(?=\\n)")[,1]
  AD <- str_match(MT, "(?<=Account Domain:\\t\\t).*?(?=\\n)")[,1]
  WSN <- str_match(MT, "(?<=Workstation Name:\\t\\t).*?(?=\\n)")[,1]
  SA <- str_match(MT, "(?<=Source Network Address:\\t\\t).*?(?=\\n)")[,1]
  
  # 追加新行到结果表,不覆盖原有列
  LogEvents.df <- rbind(
    LogEvents.df,
    data.frame(
      EV = EV, DT = DT, AN = AN, AD = AD, WSN = WSN, SA = SA,
      stringsAsFactors = FALSE
    )
  )
}

# 查看最终解析结果
View(LogEvents.df)

修正要点说明:

  • 放弃写死索引的取值方式,直接遍历每个独立事件节点,用xml_text()提取节点文本,解析容错性更高。
  • 初始化空结果数据框,匹配到目标事件时用rbind()追加新行,避免整列覆盖的问题。
  • 修正条件判断逻辑,非目标事件直接跳过,避免无效数据写入。
  • 处理str_match()返回矩阵的问题,统一取第一列匹配值,避免后续类型判断出错。

内容的提问来源于stack exchange,提问作者Bill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 07:54:24