【问题标题】:Melting repeated child nodes XML into a tidy data set using R使用 R 将重复的子节点 XML 融合成一个整洁的数据集
【发布时间】:2015-05-23 15:54:55
【问题描述】:

我正在尝试从 R 中的各种安全控件构建数据混搭。我在输出 CSV、JSON 等的设备上取得了巨大的成功,但 XML 真的让我很头疼。您很快就会发现我不是我希望成为的老板 R 开发人员,但我非常感谢曾经提供的任何帮助。这是我要解析的 XML 的简化版本。

 <devices>
    <host id="169274" persistent_id="21741">
      <ip>some_IP_here</ip>
      <hostname>Some_DNS_name_here </hostname>
      <netbiosname>Some_NetBios_Name_here</netbiosname>
      <hscore>663</hscore>
      <howner>4</howner>
      <assetvalue>4</assetvalue>
      <os>Unix Variant</os>
      <nbtshares/>
      <fndvuln id="534" port="80" proto="tcp"/>
      <fndvuln id="1191" port="22" proto="tcp"/>
    </host>
    <host id="169275" persistent_id="21003">
      <ip>some_IP_here</ip>
      <hostname>Some_DNS_name_here </hostname>
      <netbiosname>Some_NetBios_Name_here</netbiosname>
      <hscore>0</hscore>
      <howner>4</howner>
      <assetvalue>4</assetvalue>
      <os>OS Undetermined</os>
      <nbtshares/>
      <fndvuln id="5452" port="ip" proto="ip"/>
      <fndvuln id="5092" port="123" proto="udp"/>
      <fndvuln id="16157" port="123" proto="udp"/>
    </host>
</devices>

我希望实现的最终结果是一个整洁的 R 数据框,可用于分析。它的完美世界想如下

host           ip            hostname            netbiosname     VulnID   port   protocol
1 169274 some_IP_here Some_DNS_name_here  Some_NetBios_Name_here  534      80     tcp
2 169274 some_IP_here Some_DNS_name_here  Some_NetBios_Name_here  1191     22     tcp
3 169275 some_IP_here Some_DNS_name_here  Some_NetBios_Name_here  5452     ip     ip
4 169275 some_IP_here Some_DNS_name_here  Some_NetBios_Name_here  5092     123    udp
5 169275 some_IP_here Some_DNS_name_here  Some_NetBios_Name_here  16157    123    udp

在最简单的层面上,我可以毫无问题地解析 XML 并提取构建基本数据框所需的数据。但是,我很难解决如何遍历解析的 XML 并在每次 fndvuln 元素出现在父 XML 节点中时创建一个单独的行。

到目前为止,我猜最好单独加载每个元素,然后在最后绑定它们。我认为这将允许我使用 sapply 来运行 fndvuln 的各种实例并创建一个单独的条目。到目前为止,我的基本结构是这样的:

library(XML)

setwd("My_file_location_here")

xmlfile <- "vuln.xml"
xmldoc <- xmlParse(xmlfile)
vuln <-getNodeSet(xmldoc, "//host")
x <- lapply(vuln, function(x)  data.frame(host = xpathSApply(x, "." , xmlGetAttr, "id"),
                                        ip = xpathSApply(x, ".//ip", xmlValue),
                                        hostname = xpathSApply(x, ".//hostname", xmlValue),
                                        netbiosname = xpathSApply(x, ".//netbiosname", xmlValue) ))

do.call("rbind", x)

这基本上给了我这个:

    host           ip            hostname            netbiosname
1 169274 some_IP_here Some_DNS_name_here  Some_NetBios_Name_here
2 169275 some_IP_here Some_DNS_name_here  Some_NetBios_Name_here

不知道我将如何去做剩下的事情。此外,因为这个设备会弹出一个相当大的 XML 文件,所以知道如何有效地执行此操作将是我的最终目标。

【问题讨论】:

  • 您介意提一下网络链接吗?
  • 您将需要创建第二个带有 ip 和端口的 data.frame,然后将其合并到您已经创建的那个。

标签: xml r xml-parsing


【解决方案1】:

将 fndvuln 元素添加到 data.frame 时,主机、ip、主机名等将重复(尝试data.frame("a", 1:3)

x <- lapply(vuln, function(x)  data.frame(
    host = xpathSApply(x, "." , xmlGetAttr, "id"),
     ip  = xpathSApply(x, ".//ip", xmlValue),
hostname = xpathSApply(x, ".//hostname", xmlValue),
  VulnID = xpathSApply(x, ".//fndvuln" , xmlGetAttr, "id"),
   port  = xpathSApply(x, ".//fndvuln" , xmlGetAttr, "port") ))

do.call("rbind", x)
    host           ip            hostname VulnID port
1 169274 some_IP_here Some_DNS_name_here     534   80
2 169274 some_IP_here Some_DNS_name_here    1191   22
3 169275 some_IP_here Some_DNS_name_here    5452   ip
4 169275 some_IP_here Some_DNS_name_here    5092  123
5 169275 some_IP_here Some_DNS_name_here   16157  123

【讨论】:

  • 嗨,克里斯,这一切现在都很有意义。非常感谢您的帮助。
猜你喜欢
  • 2015-04-28
  • 1970-01-01
  • 1970-01-01
  • 2020-07-29
  • 2019-04-11
  • 1970-01-01
  • 2022-08-15
  • 1970-01-01
  • 2015-07-28
相关资源
最近更新 更多