2016-04-13 13 views
0

特定のデータをXMLファイルからRデータフレームに抽出します。私は後でAnoto Penによってデジタル化されたペンストロークを再構築するためにこのデータを使用したいと思います。 これまでライブラリ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>を最低1つ持っています。最大100各<stroke>ノードには、それぞれノード<sample>があります。サンプルノードからx、y、および時間データを抽出して、データフレーム内の対応するストロークに割り当てることができます。 は例えば、私はちょうど

mysamples <- xml_nodes(stroke, "sample") 

を行う場合、私はすべてのストロークからすべてのサンプルを受け取ったが、私は異なるストロークを区別する必要があります。 私は、for-loopを使って異なるストロークを反復する関数を書くことを考えましたが、これは実現できませんでした。

2つの<stroke>ノードを持つ短縮されたXMLファイルサンプルです。

<?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

現在、境界データフレームはストロークをキャプチャしません。 2つのデータフレームが必要ですか:列として識別されたストロークデータを持つ範囲とサンプル? 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)が機能するためには、プロセス全体の値が数値でも文字でも因子ではないため、data.frame定義のstringsAsFactors = FALSEパラメータが重要です。 これは良い学習経験でした。

+0

これは私にとって素晴らしい仕事でした!ありがとう! as.numeric関数は私の時間値をstyに変換して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 

は、この情報がお役に立てば幸い!

関連する問題