6

私はBluetoothカメラとインターフェースするAndroidアプリに取り組んでいます。カメラに保存されているクリップごとに、クリップに関するいくつかのフィールド(ユーザーが変更できるフィールド)をXMLファイルに保存します。

現在、このアプリはこのxmlデータをデバイスに書き込む唯一のアプリですが、将来的にはデスクトップアプリまたはiPhoneアプリもここにデータを書き込む可能性があります。別のアプリにも追加のフィールドを含めることができないと仮定したくありません(特に、このバージョンがまだサポートしていない新しいフィールドを追加した新しいバージョンのアプリがある場合)。

したがって、私が防ぎたいのは、別のアプリケーションでこのXMLファイルに新しいフィールドを追加し、ユーザーがAndroidアプリを使用して、他のフィールドを知らないためにそれらのフィールドを消去するという状況です。

それでは、架空の例を見てみましょう。

<data>
  <title>My Title</title>
  <date>12/24/2012</date>
  <category>Blah</category>
</data>

デバイスから読み取ると、これは次のようなClipオブジェクトに変換されます(簡潔にするために簡略化されています)

public class Clip {
  public String title, category;
  public Date date;
}

そのため、SAXを使用してデータを解析し、クリップに保存しています。文字をStringBuilderに保存し、title、category、dateのend要素に到達したときにそれらを書き出すだけです。

しかし、このデータをデバイスに書き戻すときに、元のドキュメントに他のタグがあった場合、私が知っているフィールドのみを書き出すため、それらは書き込まれないことに気付きました。

これにより、SAXは間違ったオプションである可能性があり、DOMなど、元々存在していた他の要素をより簡単に書き出すことができるものを使用する必要があると思います。

あるいは、Clipクラスに一般的なXMLタイプ(おそらくDOM)のArrayListが含まれているのではないかと考えていました。startTagで、要素が事前定義されたタグの1つではないかどうかを確認し、含まれている場合は、そのタグの最後に到達するまで構造全体を保存します(ただし、何に保存しますか?)。次に、書き戻すときに、追加のタグをすべて調べて、xmlファイルに書きます(もちろん、知っているフィールドと一緒に)。

これはよく知られた解決策の一般的な問題ですか?

-更新5/22/12-

実際のxmlではルートノード(実際にはアノテーションと呼ばれます)で、1に設定されたバージョン番号を使用していることは言及しませんでした。短期的には、アプリのバージョン番号が必要です。サポートは>=xmlデータのバージョン番号です。xmlの数値が大きい場合は、読み取りのために解析を試みますが、モデルへの保存は拒否します。これを行う方法については、私はまだあらゆる種類の実用的な例に興味があります。

ところで、私はかなり簡単なはずの別の解決策を考えました。XPATHを使用して、知っているノードを見つけ、データが更新されたときにそれらのノードのコンテンツを置き換えることができると思います。ただし、いくつかのベンチマークを実行したところ、メモリに解析されるときにxmlを解析する際のオーバーヘッドはばかげています。ルックアップを行わずに解析操作を行うだけで、パフォーマンスはSAXの20分の1になりました。xpathの使用は、解析で一般に30〜50倍遅くなりました。これは、リストビューで解析することを考えると非常に悪い結果でした。したがって、私の考えは、SAXを保持してノードをクリップに解析することですが、XML全体をClipクラスの変数に格納します(このxmlは短く、2kb未満であることを忘れないでください)。次に、データを書き戻すときに、XPATHを使用して、元のXMLで認識しているノードを置き換えることができます。

ただし、他のソリューションにはまだ関心があります。いくつかのコード例が含まれていない限り、私はおそらく解決策を受け入れません。

4

4 に答える 4

1

「消費」していないノードを保持したい場合は、SAXはおそらく最良のオプションではないと言うのは正しいです。SAXイベントを保持して再生するある種の「saxストア」を使用してそれを行うこともできますが(そのようなものの実装はいくつかあります)、オブジェクトモデルベースのAPIの方がはるかに使いやすくなります。 d完全なオブジェクトモデルを簡単に保持し、「自分の」ノードを更新するだけです。

もちろん、標準のDOMを使用することもできますが、任意のデータモデルで使用する特定のノードに簡単にアクセスできる代替案を検討することもできます。その中で、JDOM(http://www.jdom.org/)とXOM(http://www.xom.nu/)は興味深い候補です。

于 2012-05-22T18:13:12.213 に答える
1

SAXフィルターを使用してこれを実行する方法は次のとおりです。

  1. SAXを使用してドキュメントを読むと、すべてのイベントが記録されます。それらを録音し、SAXリーダーの次のレベルにさらにバブルアップします。基本的に、2層のSAXリーダー(XMLFilterを使用)をスタックします。1つは記録と中継を行い、もう1つはオブジェクトを作成する現在のSAXハンドラーです。
  2. 変更をディスクに書き戻す準備ができたら、ライターでレイヤー化された記録されたSAXイベントを起動し、変更した値/ノードを上書きします。

私はそのアイデアにしばらく時間を費やし、それはうまくいきました。それは基本的にXMLFiltersの適切な連鎖に帰着しました。単体テストは次のようになります。コードは次のようになります。

final SAXParserFactory factory = SAXParserFactory.newInstance();
final SAXParser parser = factory.newSAXParser();

final RecorderProxy recorder = new RecorderProxy(parser.getXMLReader());
final ClipHolder clipHolder = new ClipHolder(recorder);

clipHolder.parse(new InputSource(new StringReader(srcXml)));

assertTrue(recorder.hasRecordingToReplay());

final Clip clip = clipHolder.getClip();
assertNotNull(clip);
assertEquals(clip.title, "My Title");
assertEquals(clip.category, "Blah!");
assertEquals(clip.date, Clip.DATE_FORMAT.parse("12/24/2012"));

clip.title = "My Title Updated";
clip.category = "Something else";

final ClipSerializer serializer = new ClipSerializer(recorder);
serializer.setClip(clip);

final TransformerFactory xsltFactory = TransformerFactory.newInstance();
final Transformer t = xsltFactory.newTransformer();
final StringWriter outXmlBuffer = new StringWriter();

t.transform(new SAXSource(serializer, 
            new InputSource()), new StreamResult(outXmlBuffer));

assertEquals(targetXml, outXmlBuffer.getBuffer().toString());

重要な行は次のとおりです。

  • SAXイベントレコーダーはSAXパーサーにラップされています
  • Clipパーサー(ClipHolder)がレコーダーにラップされている
  • XMLが解析されると、レコーダーはすべてを記録し、あなたClipHolderはそれが知っていることだけを見るでしょう
  • 次に、オブジェクトで必要なことは何でもしますclip
  • 次に、シリアライザーはレコーダーにラップされます(基本的にはそれ自体に再マッピングされます)
  • 次に、シリアライザーを操作すると、記録されたイベント(親に委任し、selfとして登録ContentHandler)に、オブジェクトについての説明を重ねてフィードする処理が行われclipます。

githubでDVRコードとClipテストオーバーを見つけてください。お役に立てば幸いです。

psこれは一般的なソリューションではなく、レコード->再生+オーバーレイの概念全体は、提供されている実装では非常に基本的なものです。基本的にイラスト。XMLがより複雑で「毛深い」場合(たとえば、異なるレベルの同じ要素名など)、ロジックを拡張する必要があります。ただし、コンセプトは変わりません。

于 2012-05-23T21:25:58.363 に答える
0

特定のxmlスキーマにバインドされていない場合は、次のようなことを検討する必要があります。

<data>
    <element id="title">
        myTitle
    </element>
    <element id="date">
         18/05/2012
    </element>
    ...
</data>

次に、これらすべての要素を単一のArrayListに格納します。このようにして、情報を失うことはなく、表示したい要素を選択する可能性があります-編集-など...

于 2012-05-18T08:01:27.400 に答える
0

XPathがSAX解析よりも20倍遅いという仮定には欠陥があります...SAX解析は、処理ロジックが構築される低レベルのトークナイザーです...そして処理ロジックには追加の解析が必要です...XPathのパフォーマンスには多くの利点があります私の知る限り、vtd-xmlのXPathは一般的なDOMよりも少なくとも1桁高速であり、ヘビーデューティーXML処理にはるかに適しています...以下にいくつかのリンクを示します。さらなる参考文献...

http://sdiwc.us/digitlib/journal_paper.php?paper=00000582.pdf

Android-XPathの評価が非常に遅い

于 2016-04-22T06:36:12.293 に答える