我有一个xml数据文件,用户在其中打开了一个帐户,在某些情况下该帐户已终止。尚未终止帐户时,数据不会列出值,这使得提取信息非常困难。
这是可复制的示例(只有用户1和3的帐户被终止了):
library(XML)
my_xml <- xmlParse('<accounts>
<user>
<id>1</id>
<start>2015-01-01</start>
<termination>2015-01-21</termination>
</user>
<user>
<id>2</id>
<start>2015-01-01</start>
</user>
<user>
<id>3</id>
<start>2015-02-01</start>
<termination>2015-04-21</termination>
</user>
<user>
<id>4</id>
<start>2015-03-01</start>
</user>
<user>
<id>5</id>
<start>2015-04-01</start>
</user>
</accounts>')
要创建一个我尝试使用sapply
的data.frame,但是由于在用户没有终止值时它不会返回NA,因此代码会生成一个error: arguments imply differing number of rows: 5, 2
accounts <- data.frame(id=sapply(my_xml["//user//id"], xmlValue),
start=sapply(my_xml["//user//start"], xmlValue),
termination=sapply(my_xml["//user//termination"], xmlValue)
)
关于如何解决此问题的任何建议?
答案 0 :(得分:1)
相对于XML包,我更喜欢使用xml2包,我发现语法更易于使用。这是一个直接的问题。查找所有用户节点,然后解析id和终止节点。使用xml2,如果找不到该节点,xml_find_first
函数将返回NA。
library(xml2)
my_xml <- read_xml('<accounts>
<user>
<id>1</id>
<start>2015-01-01</start>
<termination>2015-01-21</termination>
</user>
<user>
<id>2</id>
<start>2015-01-01</start>
</user>
<user>
<id>3</id>
<start>2015-02-01</start>
<termination>2015-04-21</termination>
</user>
<user>
<id>4</id>
<start>2015-03-01</start>
</user>
<user>
<id>5</id>
<start>2015-04-01</start>
</user>
</accounts>')
usernodes<-xml_find_all(my_xml, ".//user")
ids<-sapply(usernodes, function(n){xml_text(xml_find_first(n, ".//id"))})
terms<-sapply(usernodes, function(n){xml_text(xml_find_first(n, ".//termination"))})
answer<-data.frame(ids, terms)
答案 1 :(得分:0)
我设法从XPath in R: return NA if node is missing找到了解决方案
accounts <- data.frame(id=sapply(my_xml["//user//id"], xmlValue),
start=sapply(my_xml["//user//start"], xmlValue),
termination=sapply(xpathApply(my_xml, "//user",
function(x){
if("termination" %in% names(x))
xmlValue(x[["termination"]])
else NA}), function(x) x))