9

私はServicestack.TextLibraryを学んでいます。これは、いくつかの最高の機能を備えているためです。XMLを以下のようにDTOの1つに逆シリアル化しようとしています。

C#コード: [コンソールアプリケーションに関連するコードはこちら]

class Program
    {
        static void Main(string[] args)
        {
            string str = "http://static.cricinfo.com/rss/livescores.xml";
            WebClient w = new WebClient();
            string xml = w.DownloadString(str);
            Response rss = xml.FromXml<Response>();
            foreach (var item in rss.rss.Channel.item)
            {
                Console.WriteLine(item.title);
            }
            Console.Read();
        }
    }

str[プログラムで与えられた]でXMLファイルを調べることができます。デシリアライズ用のDTOを用意しました。それらは以下の通りです:

public  class Response
{
   public RSS rss { get; set; }
}

public class RSS
{
   public string Version { get; set; }
   public ChannelClass Channel { get; set; }
}

public class ChannelClass
{
   public string title { get; set; }
   public string ttl { get; set; }
   public string description { get; set; }
   public string link { get; set; }
   public string copyright { get; set; }
   public string language { get; set; }
   public string pubDate { get; set; }
   public List<ItemClass> item { get; set; }
}

public class ItemClass
{
   public string title { get; set; }
   public string link { get; set; }
   public string description { get; set; }
   public string guid { get; set; }
}

プログラムを実行すると、次のような例外が発生します。

ここに画像の説明を入力してください

したがって、とを変更するためElementnamespace、次の回避策を実行しました。

私は以下のようDataContractAttributeに私のクラスに入れました:Response

[DataContract(Namespace = "")]
public  class Response
{
   public RSS rss { get; set; }
}

Elementデシリアライズ直前に次の2行を追加して名前を以下のように変更しました

  //To change rss Element to Response as in Exception
  xml = xml.Replace("<rss version=\"2.0\">","<Response>");
  //For closing tag
  xml = xml.Replace("</rss>","</Response>");

rssただし、逆シリアル化されたオブジェクトはであったため、foreachループで別の例外が発生しましたnull。では、どのように使用して適切な方法で逆シリアル化する必要がありServicestack.Textますか?

ノート :

他のライブラリで逆シリアル化する方法をよく知っています。ServiceStackでのみ逆シリアル化したいと思います。

4

2 に答える 2

24

TLDR:XmlSerializer制御できないxml方言から逆シリアル化するために使用します。ServiceStackコードファースト開発用に設計されており、汎用のxml解析に適合させることはできません。


ServiceStack.Textは、カスタムXmlシリアライザーを実装していませDataContractSerializer-内部で使用します。 FromXml単なる構文糖衣です。

DataContractSerializerXmlの解析に使用

お気づきのように、名前空間DataContractSerializerについては気が利いています。1つのアプローチは、クラスで名前空間を明示的に指定することですが、これを行う場合は、何かが明示的であると想定されるため、どこでも指定する必要があります。アセンブリレベルの属性(AssemblyInfo.csなど)を使用してこの問題を回避し、デフォルトの名前空間を宣言できます。[DataMember]

[assembly: ContractNamespace("", ClrNamespace = "My.Namespace.Here")]

これにより、名前空間の問題が解決されます。

ただし、DataContractSerializerで他の2つの問題を解決することはできません。

  • 属性は使用されません(あなたの場合、version
  • のようなコレクションにはitem、ラッピング名と要素名(アイテムやアイテムなど)の両方が必要です。

DataContractSerializerは汎用XMLパーサーではないため、これらの制限を回避することはできません。これは、任意のXMLを.NETデータ構造にマップするのではなく、APIを簡単に作成して使用することを目的としています。rssを解析するためにそれを取得することは決してありません。したがって、ServiceStack.Text(ラップするだけ)も解析できません。

代わりに、を使用してXmlSerializerください。

使用するXmlSerializer

これはかなり簡単です。次の行に沿って何かを使用して入力を解析できます。

var serializer = new XmlSerializer(typeof(RSS));
RSS rss = (RSS)serializer.Deserialize(myXmlReaderHere);

秘訣は、xml方言と一致するようにさまざまなフィールドに注釈を付けることです。たとえば、あなたの場合、それは次のようになります。

[XmlRoot("rss")]
public class RSS
{
    [XmlAttribute]
    public string version { get; set; }
    public ChannelClass channel { get; set; }
}

public class ChannelClass
{
    public string title { get; set; }
    public string ttl { get; set; }
    public string description { get; set; }
    public string link { get; set; }
    public string copyright { get; set; }
    public string language { get; set; }
    public string pubDate { get; set; }
    [XmlElement]
    public List<ItemClass> item { get; set; }
}

public class ItemClass
{
    public string title { get; set; }
    public string link { get; set; }
    public string description { get; set; }
    public string guid { get; set; }
}

したがって、必要に応じてXMLを解析するには、いくつかの賢明な属性で十分です。

要約すると、ServiceStackを使用するため、これにServiceStackを使用することはできませんDataContractSerializer。ServiceStack/DataContractSerializerは、スキーマを制御するシナリオ向けに設計されています。 代わりに使用してください。XmlSerializer

于 2013-02-21T18:19:13.167 に答える
0

いくつかのこと:

  1. [DataContract]属性を使用しているため。[DataMember]属性にDTOプロパティを含める必要があります。そうしないと、シリアル化/逆シリアル化プロセスでスキップされます。XMLで指定されているアセンブリ属性を使用する逆シリアル化は、xmlの名前空間でのみ機能します

  2. 代わりに、応答内にrssをラップするか、それを置き換えるために、xml操作を変更する必要があります。

    xml = xml.Replace("<rss version=\"2.0\">", "<Response><rss version=\"2.0\">");

  3. テストResponseオブジェクトを自分で作成し、ServiceStackの.ToXml()メソッドを使用してXMLにセリライズして、期待される形式を確認することをお勧めします。サービススタックがチャネルアイテムをアイテムの子リストとして処理することがわかります。これは、RSSがチャネルアイテムをフォーマットする方法ではありません。すべてのアイテムをというノードにラップする必要があります<ItemClass>

于 2013-02-18T18:50:30.867 に答える