2013-08-30 110 views
1

如果我有R中加載XML,例如:解析不規則的XML中的R

library(XML) 
top <- newXMLNode("top") 
tvp <- newXMLNode("TVP", parent = top) 
time <- newXMLNode("time", "2012-01-01", parent = tvp) 
value <- newXMLNode("value", "123", parent = tvp) 
comment <- newXMLNode("comment",parent = tvp) 
qualifer <-newXMLNode("qualifier", attrs = c(y = 'abc'), parent = comment) 
commentText <-newXMLNode("info", attrs = c(y = 'something'), parent = comment) 
tvp <- newXMLNode("TVP", parent = top) 
time <- newXMLNode("time", "2012-01-02", parent = tvp) 
value <- newXMLNode("value", "456", parent = tvp) 
tvp <- newXMLNode("TVP", parent = top) 
time <- newXMLNode("time", "2012-01-03", parent = tvp) 
value <- newXMLNode("value", "789", parent = tvp) 
comment <- newXMLNode("comment",parent = tvp) 
newXMLNode("qualifier", attrs = c(y = 'efg'), parent = comment) 
top 

生成的XML:

<top> 
    <TVP> 
    <time>2012-01-01</time> 
    <value>123</value> 
    <comment> 
     <qualifier y="abc"/> 
     <info y="something"/> 
    </comment> 
    </TVP> 
    <TVP> 
    <time>2012-01-02</time> 
    <value>456</value> 
    </TVP> 
    <TVP> 
    <time>2012-01-03</time> 
    <value>789</value> 
    <comment> 
     <qualifier y="efg"/> 
    </comment> 
    </TVP> 
</top> 

我怎樣才能得到一個數據框是正確(即在正確的。地方)包括限定詞和信息屬性?

這幾乎工作,但不完全:

DF <- xmlToDataFrame(top,stringsAsFactors=FALSE) 

結果是這樣的:

 time value comment 
1 2012-01-01 123   
2 2012-01-02 456 <NA> 
3 2012-01-03 789 

我如何獲得:

我真正需要的是一種方式來獲得的評論的子節點屬性:

 time value qualifer  info 
1 2012-01-01 123  abc something 
2 2012-01-02 456     
3 2012-01-03 789  efg 
+0

側問題/評論/警告 - 這些線路兩者碰撞RStudio: '限定符< - xpathApply(頂部, 「//限定符/ @ y」)的'' 限定符< - xpathApply(xmlRoot(top),「// qualifier/@ y」) 我不知道爲什麼。 – JPMac

回答

1

請嘗試以下操作。對於每個TVP找到所有後代葉利用在當前TVP節點的.//*[not(*)] xpath表達式,其中.裝置在當前點開始,即,和//*手段遍歷所有後代但[not(*)]它限制到僅具有沒有孩子的那些。然後爲每個TVP創建一個值列表(或者如果沒有值,則爲屬性)一個列表組件。在最後一行是每個列表組件轉換成一個矩陣,並使用plyr的rbind.fill.matrix把矩陣一起:

xp <- xpathApply(top, "/top/TVP", xpathSApply, ".//*[not(*)]", function(x) 
     setNames(ifelse(nzchar(xmlValue(x)), xmlValue(x), xmlAttrs(x)), xmlName(x))) 
library(plyr) 
do.call(rbind.fill.matrix, lapply(xp, t)) 

順便說一句,我的Windows圖形用戶界面系統(無RStudio)對您的評論的代碼也應聲。

UPDATE:溶液的次要縮短

+0

我從來沒有見過setNames,但它立即進入我的劇目(太棒了!)。我不遵循:'.//*[not(*)]'在做什麼......但它有效。 – JPMac

+0

已經添加了該xpath表達式的一些解釋。 –

1

試試下面的代碼:

require(plyr) ### provides rbind.fill 
getDataframe <- function(xml){ 
out2 <- xmlSApply(xml,function(x){ 
out <- xmlSApply(x, function(y){ 
    if(length(xmlChildren(y)) > 1){xmlSApply(y,xmlAttrs) 
    }else{xmlValue(y)}}) 
    as.data.frame(t(unlist(out))) ## rbind.fill likes dataframes 
    }) 
    return(do.call(rbind.fill,out2)) 
} 
getDataframe(top) 

這裏的想法是:

  • 檢查如果XML組件有子;然後用xmlAttrs
  • 如果沒有孩子使用xmlValue
  • 這給了我們一個清單,但我們需要一個data.frame
  • 由於某些價值觀缺失,我們從plyr包
  • 最後rbind.fill需要我們需要一些智能轉換(as.data.frame)使rbind.fill開心
+0

不錯。我假設'return(do.call(rbind.fill,out3))'應該是'return(do.call(rbind.fill,out2))'?另外,它沒有選擇最後一個限定符('efg',它只有一個孩子)。我的猜測是,if(length(xmlChildren(y))> 1)'應該是類似於if(length(xmlChildren(y))> = 1)'......但是當我這樣做時,我得到一個錯誤....我仍然在搞這個。 – JPMac

+0

是的;它應該是out0 –