2016-04-13 21 views
0

我想將XML文件中的特定數據提取到R數據框。我想稍後使用這些數據來重建Anoto筆的數字化筆畫。 到目前爲止,我通過使用庫rvest來做到這一點。 (示例XML文件可以在下面找到)R&XML - 將數據分配給在數據框中同名的正確父節點

library(rvest) 

file <- read_xml("1.xml") 

#The interesting data is in the stroke nodes. 
stroke <- xml_nodes(file, "stroke") 

#One example for extracting data I am interested in. 
bounds <- xml_nodes(stroke, "bounds") 
x <- xml_text(xml_nodes(bounds, "x")) 
y <- xml_text(xml_nodes(bounds, "y")) 
width <- xml_text(xml_nodes(bounds, "width")) 
height <- xml_text(xml_nodes(bounds, "height")) 

#Putting this data into a Dataframe. 
df <- data.frame(x, y, width, height) 

到目前爲止好。我現在的問題是<sample>節點。在XML文件中,我有一個<stroke>節點的最小數量,最多可達約。最大100每個<stroke>節點都有自己的<sample>節點。我想以一種方式從樣本節點中提取x,y和時間數據,我可以將它們分配給數據框中的相應筆劃。 例如,如果我只是做

mysamples <- xml_nodes(stroke, "sample") 

我收到的所有樣本都招,但我有不同的筆觸來區分。 我想過編寫一個使用for循環遍歷不同筆畫的函數,但是我無法完成這個任務。

這是一個簡短的XML文件示例,其中包含兩個<stroke>節點。

<?xml version="1.0" encoding="UTF-8" ?> 
 
<page> 
 
    <UnassignedStrokes> 
 
    <starttime>1459867893629</starttime> 
 
    <endtime>1459867896812</endtime> 
 
    <stroke> 
 
     <starttime>1459867893629</starttime> 
 
     <endtime>1459867894815</endtime> 
 
     <linewidth>1.0</linewidth> 
 
     <color>-14090101</color> 
 
     <bounds> 
 
     <x>260.0</x> 
 
     <y>750.0</y> 
 
     <width>217.0</width> 
 
     <height>18.0</height> 
 
     </bounds> 
 
     <sample> 
 
     <x>260.625</x> 
 
     <y>766.0</y> 
 
     <time>1459867893629</time> 
 
     <force>108</force> 
 
     </sample> 
 
     <sample> 
 
     <x>260.625</x> 
 
     <y>763.625</y> 
 
     <time>1459867893722</time> 
 
     <force>120</force> 
 
     </sample> 
 
     <sample> 
 
     <x>262.875</x> 
 
     <y>762.0</y> 
 
     <time>1459867893775</time> 
 
     <force>122</force> 
 
     </sample> 
 
    </stroke> 
 
    <stroke> 
 
     <starttime>1459867895892</starttime> 
 
     <endtime>1459867896812</endtime> 
 
     <linewidth>1.0</linewidth> 
 
     <color>-14090101</color> 
 
     <bounds> 
 
     <x>364.0</x> 
 
     <y>701.0</y> 
 
     <width>10.0</width> 
 
     <height>125.0</height> 
 
     </bounds> 
 
     <sample> 
 
     <x>364.5</x> 
 
     <y>701.0</y> 
 
     <time>1459867895892</time> 
 
     <force>32</force> 
 
     </sample> 
 
     <sample> 
 
     <x>366.0</x> 
 
     <y>702.0</y> 
 
     <time>1459867895905</time> 
 
     <force>106</force> 
 
     </sample> 
 
     <sample> 
 
     <x>367.25</x> 
 
     <y>702.625</y> 
 
     <time>1459867895958</time> 
 
     <force>120</force> 
 
     </sample> 
 
    </stroke> 
 
    </UnassignedStrokes> 
 
</page>

我高度讚賞任何幫助!

+0

當前您的界限數據框不捕捉筆畫。你是否需要兩個數據框:邊界和樣本以筆劃數據標識爲列?在XML中,兩者都是彼此的兄弟姐妹。請顯示所需的最終結果。 – Parfait

回答

1

該解決方案將生成一個單一的數據框,將「邊界」數據框與來自所有子節點的樣本信息連接在一起。這是周圍的邊緣有點粗糙通過它的工作原理:

#Putting this data into a Dataframe. 
df<-data.frame(x, y, width, height, stringsAsFactors=FALSE) 

#list of of subnodes 
samples<-sapply(stroke, FUN=xml_nodes, xpath="sample") 
#find list of lists for x, y, time and force from each subnode of interest 
sx<-sapply(samples, FUN=function(x) {xml_text(xml_nodes(x, xpath="x"))}) 
sy<-sapply(samples, FUN=function(x) {xml_text(xml_nodes(x, xpath="y"))}) 
stime<-sapply(samples, FUN=function(x) {xml_text(xml_nodes(x, xpath="time"))}) 
sforce<-sapply(samples, FUN=function(x) {xml_text(xml_nodes(x, xpath="force"))}) 

#create dataframe from the parent df and the list of lists of subnodes 
results<-lapply(seq(1:length(sx)), function(i){data.frame(df[i,],sx=unlist(sx[i]), 
     sy=unlist(sy[i]), force=unlist(sforce[i]), time=unlist(stime[i]), 
                   stringsAsFactors=FALSE)}) 
#create a single df 
finaldf<-do.call(rbind, results) 
#convert all columns to numeric values 
finaldf[,1:ncol(finaldf)]<-lapply(finaldf[,1:ncol(finaldf)], as.numeric) 

這會產生一些警告,但這些可以忽略不計。對於do.call(rbind)來說,重要的是整個過程中的值是數字或字符而不是因素,因此stringsAsFactors = data.frame定義中的FALSE參數。 這是一個很好的學習經驗。

+0

這對我很好!謝謝!即使as.numeric函數使得我的時間值轉換爲像1.523526e + 12的值,這不是很好...有一個想法如何防止這種情況? – Flugmango

+0

根據UNIX的數據,這個數字很可能是從1970年1月1日開始的毫秒數。我將除以1000並插入:as.POSIXct(x,origin =「1970-01-01」)。您可能需要根據時區進行調整。 – Dave2e

1

不知道如果有一個更簡單的方法,但是這是最好的解決方案,我想出來的:

require(rvest) 
require(data.table) 

strokes <- read_xml("test.xml") %>% xml_nodes("stroke") 

# iterate over stroke nodes 
tmp <- lapply(strokes, function(x){ 

    # get all sample nodes 
    samples <- x %>% xml_nodes("sample") 

    # iterate over samples in stroke and extract information 
    tmp.s <- lapply(samples, function(s){ 
    children <- xml_children(s) 
    data.frame(name = xml_name(children), text = xml_text(children)) 
    }) 

    # bind samples together and give them the appropriate ID 
    tmp.s <- rbindlist(tmp.s, idcol = "sample") 
    tmp.s 
}) 

# bind strokes together and give them the appropriate ID 
tmp <- rbindlist(tmp, idcol = "stroke") 

tmp 
    stroke sample name   text 
1:  1  1  x  260.625 
2:  1  1  y   766.0 
3:  1  1 time 1459867893629 
4:  1  1 force   108 
5:  1  2  x  260.625 
6:  1  2  y  763.625 
7:  1  2 time 1459867893722 
8:  1  2 force   120 
9:  1  3  x  262.875 
10:  1  3  y   762.0 
11:  1  3 time 1459867893775 
12:  1  3 force   122 
13:  2  1  x   364.5 
14:  2  1  y   701.0 
15:  2  1 time 1459867895892 
16:  2  1 force   32 
17:  2  2  x   366.0 
18:  2  2  y   702.0 
19:  2  2 time 1459867895905 
20:  2  2 force   106 
21:  2  3  x  367.25 
22:  2  3  y  702.625 
23:  2  3 time 1459867895958 
24:  2  3 force   120 
    stroke sample name   text 

希望這有助於!

相關問題