2016-11-09 14 views
1

入力ストリーム、つまりos.Stdin:非常に大きなXMLファイルを処理するGoプログラムがあるので処理できませんそれはすぐにすべてです。要素の「outerxml」を取得する(innerxmlのように、要素自体を含む)

私は後処理のために特定の性質を持つすべてのXML要素を抽出したいと考えています。

抽出する要素を特定し、関連する開始要素と終了要素を取得するのに問題はありません。しかし、全要素を文字列としてダンプする方法がわかりません。内側のXMLだけではありません。

例えば、想像し、私は次のXMLがあります。この例では

<a> 
    <b somethingUseful="1"> 
    <c>Hello</c> 
    <d>world</d> 
    </b> 
    <e> 
    <foo/> 
    </e> 
    <!-- Imagine there were 1 billion lines in between - 
     I need to stream this! --> 
    <b somethingUseful="321"> 
    <c>Hello again</c> 
    </b> 
</a> 

を、私は最初から最後まで、出力<b>の各要素にしたいです。

Here comes a B: 

    <c>Hello</c> 
    <d>world</d> 

Here comes a B: 

    <c>Hello again</c> 

とても近く、それは自分自身を<b>タグ(および属性)を欠けている:DecodeElementinnerxmlを使用して

は、私はストリーミング方式で、はるかにこれを取得することができますよ。私はデコードのストリーミング性を犠牲にすることなく、その最後のステップをどうやって作るかを考え出すことができませんでした。

明確にするために、私が望む出力は何かのようである:ここでは

Here comes a B: 
    <b somethingUseful="1"> 
    <c>Hello</c> 
    <d>world</d> 
    </b> 
Here comes a B: 
    <b somethingUseful="321"> 
    <c>Hello again</c> 
    </b> 

この例をenunciates遊び場だと私はここまできでやった:

https://play.golang.org/p/XqJY_1pa9j

答えて

2

、私は入力Reader 2に分割するTeeReaderを使用します要素の前後にあるdecoder.InputOffset)が発生します。メモリ使用量を最小限に抑えるために

、バッファが連続してのみ、我々は潜在的にに一致していません知っている時点までをクリアされます。我々はこれを追跡するためにオフセットを維持する。この複雑さは、デコーダが手元のトークンの前でリーダーからバイトをつかむことができるので必要です。したがって、実際に必要なものをクリアしないように注意する必要があります。それが1に戻ってクリアされる前に同時にバッファに格納することができる

  1. 最大2つのトークン:

    だから、追加のメモリ使用量は、唯一のと同じくらいです。
  2. 出力されている実際の要素のサイズ。

はここ溶液による更新遊び場です:

https://play.golang.org/p/H8WVDWI57r

1

かなり粗いアプローチは、開始要素の前と終了要素の後にデコーダにthe offsetを要求することによってオフセットを保存し、それらのバイトを読み取ることです。

this playground exampleを参照してください。リーダーは2つのパイプに分かれています。そのうちの1つはXMLデコーダに送られ、もう1つのパイプラインはバッファされ、XML要素に対応するバイト範囲を抽出するために使用されます。

XMLデコードルーチンは、チャネル上に一対のオフセットを書き込みます。チャネルのペアは、別のスレッドがリーダストリームのコピーから対象の領域をスキップまたは出力するために使用します。これはおそらく、私がやったハックの仕事よりも真剣にやるべきです。

この解決策では、Seek/ReadAtは実行可能ではないと考えています。私は恐らくファイルを2回開いたばかりの場合、これをもっと上回るでしょう。デコーダによって解析されます、標準、そして我々は出力に間にある正確な要素を(使用しますバッファ:decoder.InputOffsetの@ nothingmuchの利用状況に触発さ

+1

あー、これは素晴らしいスタートです!私はもっ​​ときれいにして、あなたに戻ってくる方法を探します:Dありがとう! –

+0

ここでは 'os.Stdin'と一緒に作業しているようですが、2つのファイルとして開くことはできません(そうする方法がない限り::O)が、扱いにくい。とにかくマルチライターがやっているようだ。 –

+0

ああ、私はあなたが 'ioutil.Discard'の愚かさにコピーする必要があると思う – nothingmuch

関連する問題