如何在R中解析XML文件的datetime属性并存入数据框?
问题描述
我在用R语言解析XML文件时,已经成功提取到了<CumulativeOperatingHours>节点下的<Hour>值(比如1059.60),但一直没法获取该节点的datetime属性值(比如"2016-12-15T22:45:40.000Z")。希望能把这个datetime属性解析出来并存入数据框,我的相关代码和XML示例如下:
我的R代码:
xmldataframe <- xmlToDataFrame("xamal.xml") xmlfile <- xmlParse("xamal.xml") rootnode <- xmlRoot(xmlfile) rootsize <- xmlSize(rootnode) print(rootsize) # [1] 103 print(rootnode[[11]][[5]]) # <CumulativeOperatingHours datetime="2016-12-15T22:45:40.000Z"> # <Hour>1059.60</Hour> # </CumulativeOperatingHours>
XML文件示例:
<?xml version="1.0" encoding="UTF-8"?> <Group xmlns="http://standards.is.com/is/151/-1" version="2" Time="2018-05-30T19:33:44.352Z"> <Links> <rel>self</rel> <href>https://cloud.com/1</href> </Links> <Links> <rel>last</rel> <href>https://cloud.com/2</href> </Links> <Links> <rel>next</rel> <href>https://cloud.com/3</href> </Links> <Equip> <EquipHead> <Name>CAST</Name> <Model>1100</Model> <EquipmentID>Desk</EquipmentID> <SerialNumber>12312312</SerialNumber> <PIN>123123</PIN> </EquipHead> <Location datetime="2012-06-25T11:14:54.000Z"> <Latitude>44.57</Latitude> <Longitude>-95.51</Longitude> </Location> <OperatingHours datetime="2012-03-01T17:42:37.000Z"> <Hour>198.80</Hour> </OperatingHours> </Equip> <Equip> <EquipHead> <Name>Yuza</Name> <Model>L208</Model> <EquipmentID>4DW772GP</EquipmentID> <SerialNumber>4DW772GP</SerialNumber> <PIN>1DW772GPVJF</PIN> </EquipHead> <Location datetime="2018-05-30T19:22:46.000Z"> <Latitude>47.518556</Latitude> <Longitude>-70.422444</Longitude> </Location> <IdleHours datetime="2018-05-30T19:02:46.000Z"> <Hour>33.74</Hour> </IdleHours> <OperatingHours datetime="2018-05-30T19:22:48.000Z"> <Hour>72.35</Hour> </OperatingHours> <Distance datetime="2018-05-30T19:02:46.000Z"> <Odometer>kilometre</Odometer> <OdometerV>30.9</OdometerV> </Distance> <FuelUsed datetime="2018-05-30T19:02:46.000Z"> <FuelUnits>litre</FuelUnits> <Consumed>395</Consumed> </FuelUsed> </Equip> <Equip> <EquipHead> <OEMName>CALL</OEMName> <Model>562A</Model> <EquipmentID>1W2772G</EquipmentID> <SerialNumber>1TT772GPTE</SerialNumber> <PIN>1MM772GPTE</PIN> </EquipHead> <Location datetime="2018-05-30T07:00:17.000Z"> <Latitude>22.809278</Latitude> <Longitude>-45.316417</Longitude> </Location> <IdleHours datetime="2018-05-24T20:37:03.000Z"> <Hour>457.10</Hour> </IdleHours> <OperatingHours datetime="2018-05-30T18:25:18.000Z"> <Hour>26.35</Hour> </OperatingHours> <Distance datetime="2018-05-23T13:26:37.000Z"> <Units>kilometre</Units> <OdometerV>5075.6997</OdometerV> </Distance> <FuelUsed datetime="2018-05-24T20:37:03.000Z"> <FuelUnits>litre</FuelUnits> <FuelConsumed>2548</FuelConsumed> </FuelUsed> </Equip> </Group>
解决方案
首先要说明:xmlToDataFrame()默认只会提取节点的文本内容,不会处理节点的属性,所以你没法直接用它拿到datetime属性。我们可以用xmlParse()结合节点遍历或者XPath查询来解决这个问题,下面给你两种实用的方法:
方法一:遍历节点提取(适合复杂结构)
这种方法适合XML结构多变的情况,可以灵活处理每个节点的属性和子节点:
library(XML) # 解析XML文件 xmlfile <- xmlParse("xamal.xml") rootnode <- xmlRoot(xmlfile) # 创建空数据框存储结果 result_df <- data.frame( EquipmentID = character(), DateTime = character(), Hour = numeric(), NodeType = character(), stringsAsFactors = FALSE ) # 遍历所有Equip节点 for (i in 1:xmlSize(rootnode)) { current_node <- rootnode[[i]] # 只处理<Equip>节点 if (xmlName(current_node) == "Equip") { # 获取设备ID equip_id <- xmlValue(current_node[["EquipHead"]][["EquipmentID"]]) # 遍历Equip下的子节点,找带datetime属性的节点 for (j in 1:xmlSize(current_node)) { child_node <- current_node[[j]] datetime_attr <- xmlAttrs(child_node)["datetime"] if (!is.null(datetime_attr)) { # 提取Hour值(如果节点下有<Hour>子节点) hour_val <- if (!is.null(child_node[["Hour"]])) { as.numeric(xmlValue(child_node[["Hour"]])) } else { NA # 没有Hour节点就填NA } # 把数据添加到数据框 result_df <- rbind(result_df, data.frame( EquipmentID = equip_id, DateTime = datetime_attr, Hour = hour_val, NodeType = xmlName(child_node), stringsAsFactors = FALSE )) } } } } # 查看结果 head(result_df)
方法二:XPath快速提取(适合目标明确)
如果你的目标只是提取<CumulativeOperatingHours>节点的datetime和<Hour>值,用XPath会更简洁高效。注意你的XML有命名空间(xmlns="http://standards.is.com/is/151/-1"),所以需要指定命名空间才能正确找到节点:
library(XML) xmlfile <- xmlParse("xamal.xml") # 定义XML的命名空间 ns <- c(is = "http://standards.is.com/is/151/-1") # 提取所有CumulativeOperatingHours节点的datetime属性 datetime_vals <- xpathSApply(xmlfile, "//is:CumulativeOperatingHours", xmlAttrs, namespaces = ns)[1,] # 提取对应的Hour值 hour_vals <- xpathSApply(xmlfile, "//is:CumulativeOperatingHours/is:Hour", xmlValue, namespaces = ns) hour_vals <- as.numeric(hour_vals) # 组合成数据框 cumulative_hours_df <- data.frame( DateTime = datetime_vals, Hour = hour_vals, stringsAsFactors = FALSE ) # 查看结果 print(cumulative_hours_df)
关键说明
- 命名空间处理:你的XML根节点带有
xmlns属性,这意味着所有子节点都属于这个命名空间,所以用XPath查询时必须通过namespaces参数指定,否则会找不到目标节点。 - 属性提取:
xmlAttrs()函数可以获取节点的所有属性,通过下标["datetime"]就能拿到指定属性的值。
内容的提问来源于stack exchange,提问作者Alli
相关产品推荐
相关产品推荐

