在R中的递归函数中向data.frame添加新行

时间:2014-12-04 03:13:31

标签: xml r recursion xml-parsing dataframe

我正在尝试使用Duncan Temple Lang的XML包来解析R中的XML。我的代码如下:

library(XML)
retrieveStructureInfo <- function(node, tableData) {  
    tableD <- data.frame(path = NA, node = NA, value = NA)

    for (i in 1 : xmlSize(xmlAttrs(node))) {
      tableD <- rbind(tableD, c("path", "node", "value"))  
      tableData <<- rbind(tableData, tableD)    
    }

    #children is the no. of nodes within a node
    for (i in 1 : children) {
      #recursive function call
      retrieveStructureInfo(node[[i]], tableD) 
    }
}

#parse xml document
#xmlfile is the file path
doc <- xmlParse(xmlfile)
r <- xmlRoot(doc)
tableData <- data.frame(path = NA, node = NA, value = NA)
retrieveStructureInfo(r, tableData)
tableData

我在向data.frame添加行时遇到问题,因为它是在递归函数中完成的。对于下面给出的XML,只有最后两个属性值被添加到data.frame,即Source =&#34; b&#34;和可用=&#34;真&#34;。我创建了一个名为tableData的主表,并尝试使用名为tableD的函数中的本地表更新它,但它不起作用。

<CATALOG>
   <PLANT>
      <COMMON Source="a" Available="false">Bloodroot</COMMON>
   </PLANT>
   <PLANT>
      <COMMON Source="b" Available="true">Columbine</COMMON>
   </PLANT>
</CATALOG>

我忘了添加我的目标是创建一个读取任何xml的函数(这就是为什么我选择了递归的想法)并给出了一个输出:

                   path                 node                  value parent      type
  CATALOG/PLANT/COMMON               Source                    a    PLANT  attribute
  CATALOG/PLANT/COMMON            Available                  false  PLANT  attribute
  CATALOG/PLANT/COMMON               COMMON              Bloodroot  PLANT       text

1 个答案:

答案 0 :(得分:0)

通常xml和递归的答案是使用xpath。您可以创建一个包含几个xpath查询的表或一个辅助函数,如xmlToList。

x<- '<CATALOG>
   <PLANT>
      <COMMON Source="a" Available="false">Bloodroot</COMMON>
   </PLANT>
   <PLANT>
      <COMMON Source="b" Available="true">Columbine</COMMON>
   </PLANT>
</CATALOG>'

doc <- xmlParse(x)

xpathSApply(doc, "//COMMON", xmlValue)
[1] "Bloodroot" "Columbine"
xpathSApply(doc, "//COMMON", xmlGetAttr, "Source")
[1] "a" "b"

y <- xmlToList(doc)
data.frame(path=names(unlist(y)),value=unlist( y) )
                           path     value
1             PLANT.COMMON.text Bloodroot
2    PLANT.COMMON..attrs.Source         a
3 PLANT.COMMON..attrs.Available     false
4             PLANT.COMMON.text Columbine
5    PLANT.COMMON..attrs.Source         b
6 PLANT.COMMON..attrs.Available      true

library(plyr)
ldply(y, data.frame)  #OR 
ldply( y, function(x) data.frame(x, names(x$COMMON$.attrs)  ) )
    .id COMMON.text COMMON..attrs names.x.COMMON..attrs.
1 PLANT   Bloodroot             a                 Source
2 PLANT   Bloodroot         false              Available
3 PLANT   Columbine             b                 Source
4 PLANT   Columbine          true              Available