2012-02-20 6 views
3

通常、オブジェクトをXMLファイルにシリアル化するために、次のコードを使用します。毎日、私はこのリストに異なる時間帯に追加される約100〜1000の新しいアイテムを持っています。古いデータを逆シリアル化せずにシリアル化されたxmlデータに新しい項目を追加する方法は?

var xmlSerializer = new XmlSerializer(typeof(List<TestModel>)); 
xmlSerializer.Serialize(stream, list); 

古いデータを逆シリアル化せずにシリアル化されたXMLデータに新しい項目を追加するにはどうすればよいですか?

おかげで、

答えて

4

オブジェクトをメモリにシリアル化して既存のファイルに追加することができます。また、MS記事Efficient Techniques for Modifying Large XML Filesをご覧ください。この記事には、お客様の状況に該当する2つの手法が記載されています。

0

私はそれが可能だとは思いません。 がシリアル化されたのシリアル化されたデータブロックへのランダムアクセスを実行したいので、順次アクセスする必要があります。 XML文書を直接変更することもできますが、これは高速になりますが、オブジェクトの追加/削除などの操作がはるかに簡単なシリアライズ/デシリアライズされたオブジェクトツリーの機能を失うことになります。

3

私が考えることができるXmlSerializerだけを使用してほしいことをする方法はありませんが、少し余分な作業がありますが、これが可能です。

簡単なアプローチは、既存のコードと同じように、その日の最初の項目のリストをシリアル化することです。新しいデータが入ったら、保存されたxmlをXmlDocumentで開き、一度に1つの項目のシリアライズを追加することができます。注意すべき

一つは、結果のXMLが非常に大きい場合には、常にXmlDocumentは非常に大きくなることが(と遅いこと、あるいはパベルKymentsコメントで指摘してOutOfMemoryExceptions引き起こす可能性)ということで、この場合には、あなたが調査することをお勧めしますXmlReaderおよびXmlWriterを使用してxmlを連続して追加します。しかし、全体的なアプローチは同じ(オープン>新しいアイテム - >追加生成されたXMLベース>再保存シリアライズ)

残る[EDITを - XmlDocumentアプローチではなく、XmlReader/XmlWriterをチェーンショーに変更コードサンプル]

これらの線に沿って何か:

public static void AppendToXml(
    Stream xmlSource,    // your existing xml - could be from a file, etc 
    Stream updatedXmlDestination, // your target xml, could be a different file 
    string rootElementName,  // the root element name of your list, e.g. TestModels 
    TestModel itemToAppend)  // the item to append 
{ 
    var writerSettings = new XmlWriterSettings {Indent = true, IndentChars = " " }; 
    using (var reader = XmlReader.Create(xmlSource)) 
    using (var writer = XmlWriter.Create(updatedXmlDestination, writerSettings)) 
    { 
     while (reader.Read()) 
     { 
      switch (reader.NodeType) 
      { 
       case XmlNodeType.XmlDeclaration: 
        break; 
       case XmlNodeType.Element: 
        writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI); 
        if (reader.HasAttributes) 
        { 
         while (reader.MoveToNextAttribute()) 
         { 
          writer.WriteAttributeString(reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value); 
         } 
        } 
        if (reader.IsEmptyElement) 
         writer.WriteEndElement(); 
        break; 
       case XmlNodeType.EndElement: 
        if (reader.Name == rootElementName) 
        { 
         var serializer = new XmlSerializer(typeof(TestModel)); 
         var ns = new XmlSerializerNamespaces(); 
         ns.Add("", ""); 
         serializer.Serialize(writer, itemToAppend, ns); 
        } 
        writer.WriteEndElement(); 
        break; 
       case XmlNodeType.Text: 
        writer.WriteRaw(SecurityElement.Escape(reader.Value)); 
        break; 
       case XmlNodeType.CDATA: 
        writer.WriteCData(reader.Value); 
        break; 
      } 
     } 
    } 
} 

注:あなたは、このような空白、コメント、PROCとして(簡潔にするためここでは省略)他のノード・タイプのサポートを追加することもできますこれらはすべて上記のCDATAと同じパターンに従います。ケースを入れ、適切なライターメソッドを呼び出します。

このアップデートされたアプローチでは、いつでもメモリの量が決して少なくなりません。

+0

私はちょうど同じことをタイプしていました。 XMLを直接操作するには、XmlReaderまたはその他のXmlクラスのいずれかを使用します。これは、最初にデシリアライズするのが最も簡単で簡単な解決策ではありませんが、ここにいるので、既にそれを済ませていると仮定します。 – sngregory

+0

注:本当に大きな文書では、文書全体をメモリにロードするため、XmlDocumentは失敗します –

+0

@PavelKymets - 確かに。上で述べたように、この場合、 'XmlReader' /' XmlWriter'を使った逐次的なアプローチが望ましいかもしれません。 –

関連する問題