将XML文件的所有子节点都添加到data.frame或data.table

时间:2016-11-01 06:29:01

标签: r xml

例如,我有以下XML代码

tt = '<Nummeraanduiding>
  <identificatie>0010200000114849</identificatie>
<aanduidingRecordInactief>N</aanduidingRecordInactief>
<aanduidingRecordCorrectie>0</aanduidingRecordCorrectie>
<huisnummer>13</huisnummer>
<officieel>N</officieel>
<postcode>9904PC</postcode>
<tijdvakgeldigheid>
<begindatumTijdvakGeldigheid>2010051100000000</begindatumTijdvakGeldigheid>
</tijdvakgeldigheid>
<inOnderzoek>N</inOnderzoek>
<typeAdresseerbaarObject>Verblijfsobject</typeAdresseerbaarObject>
<bron>
<documentdatum>20100511</documentdatum>
<documentnummer>2010/NR002F</documentnummer>
</bron>
<nummeraanduidingStatus>Naamgeving uitgegeven</nummeraanduidingStatus>
<gerelateerdeOpenbareRuimte>
<identificatie>0010300000000444</identificatie>
</gerelateerdeOpenbareRuimte>
</Nummeraanduiding> '

目标是将此节点(Nummeraanduiding)转换为data.table(或data.frame也可以)。一个挑战是我有很多这些Nummeraanduiding节点(数百万个)。

以下代码可以处理数据:

library(XML)
# This parses the doc...
doc = xmlParse(tt)
# Solution (1) - this is the most obvious solution..
XML::xmlToDataFrame(doc)
# Solution (2) - apparently converting to a list is also possible.. 
unlist(xmlToList(doc))
# Solution (3) - My own solution
data.frame(as.list(unlist(xmlToList(doc))))

并非所有解决方案都能产生预期效果......最终只有Solution(3)的版本满足了我的需求。

  1. 采用data.frame / data.table格式
  2. 它包含所有子子节点,并且每列具有不同的名称
  3. 它没有合并&#39;子女节点的信息
  4. 然而,为我的所有数据运行这段代码变得非常慢。花了8个多小时来完成一个文件,其中包含2290000倍的Nummeraanduiding&#39; -node。

    你们知道加快这个过程的方法吗?我的方法可以改进吗?我可能错过了一些有用的功能吗?

1 个答案:

答案 0 :(得分:0)

鉴于每个字段已经在单独的行中grep,请使用read.table读取剩余内容并使用tapply从长转换为宽来生成结果矩阵(如果需要,可以将其转换为数据帧或data.table)。请注意,在read.table中,我们绕过引用,注释和类处理。最后,测试一下它是否更快。没有包使用。

nms <- c("identificatie", "aanduidingRecordInactief", "aanduidingRecordCorrectie", 
"huisnummer", "officieel", "postcode", "tijdvakgeldigheid.begindatumTijdvakGeldigheid", 
"inOnderzoek", "typeAdresseerbaarObject", "bron.documentdatum", 
"bron.documentnummer", "nummeraanduidingStatus", 
"gerelateerdeOpenbareRuimte.identificatie")

rx <- paste(nms, collapse = "|")
g <- chartr("<", ">", grep(rx, readLines(textConnection(tt)), value = TRUE))

long <- read.table(text = g, sep = ">", quote = "", comment.char = "", 
  colClasses = "character")[2:3]
names(long) <- c("field", "value")
long$field <- factor(long$field, levels = nms)  # maintain order of columns
long$recno <- cumsum(long$field == "identificatie")

with(long, tapply(value, list(recno, field), c))

如果所有记录都具有完全相同的字段集,例如nms中列出的字段,则最后一行可以替换为此字段(可能更快):

matrix(long$value, ncol = length(nms), byrow = TRUE, dimnames = list(NULL, nms))

tapply行的另一种替代方法是使用基础R中的reshape或使用reshape2包中的dcast