5

XMLシリアライゼーションを使用するのはこれが初めてで、2日間トラブルシューティングを試みた後、これは私を完全に狂わせています。

逆シリアル化が開始されると、次のエラーが発生します。

The XML element 'name' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.

私のコードのこの行でエラーが発生します:

Album album = (Album)serializer.Deserialize(reader);

理由はわかりません。複製された「名前」ノードがないため、取得できません。これは、サード パーティの REST API の HttpWebResponse から受け取った XML ドキュメントです。

完全なコードは次のとおりです。

私のアルバムクラス(私がデシリアライズしているタイプ):

    public class Album
    {
        #region Constructors

        public Album() 
        { 

        }

        #endregion

        #region ElementConstants

        public static class ElementConstants
        {
            public const string aID = "aid";
            public const string Owner = "owner";
            public const string AlbumName = "name";
            public const string CoverPhotoID = "cover_pid";
            public const string CreateDate = "created";
            public const string LastModifiedDate = "modified";
            public const string Description = "description";
            public const string Location = "location";
            public const string AlbumURL = "link";
            public const string Size = "size";
            public const string Visible = "visible";
        }

        #endregion ElementConstants

        #region Public Properties

        [XmlArray(ElementName = "photos_GetAlbums_response")]
        [XmlArrayItem( "album" )]
        public Album[] Albums { get; set; }

        [XmlElement (ElementName = ElementConstants.AlbumName, DataType = "string")]
        public string AlbumID { get; set; }

        [XmlElement(ElementName = ElementConstants.aID, DataType = "int")]
        public Int32 CoverPhotoID { get; set; }

        [XmlElement(ElementName = ElementConstants.Owner, DataType = "string")]
        public string Owner { get; set; }

        [XmlElement(ElementName = ElementConstants.AlbumName, DataType = "string")]
        public string AlbumName { get; set; }

        [XmlElement(ElementName = ElementConstants.aID, DataType = "DateTime")]
        public DateTime CreateDate { get; set; }

        [XmlElement(ElementName = ElementConstants.LastModifiedDate, DataType = "DateTime")]
        public DateTime LastModifiedDate { get; set; }

        [XmlElement(ElementName = ElementConstants.Description, DataType = "string")]
        public string Description { get; set; }

        [XmlElement(ElementName = ElementConstants.Location, DataType = "string")]
        public string Location { get; set; }

        [XmlElement(ElementName = ElementConstants.AlbumURL, DataType = "string")]
        public string Link { get; set; }

        [XmlElement(ElementName = ElementConstants.Size, DataType = "size")]
        public string Size { get; set; }

        [XmlElement(ElementName = ElementConstants.Visible, DataType = "string")]
        public string Visible { get; set; }

        #endregion
    }

私のシリアライザクラス:

    public class Serializer
    {
        public static Album CreateAlbumFromXMLDoc(XmlDocument doc)
        {
            // Create an instance of a serializer
            var serializer = new XmlSerializer(typeof(Album));
            var reader = new StringReader(doc.ToString());

            // Deserialize the Xml Object and cast to type Album
            Album album = (Album)serializer.Deserialize(reader);

            return album;
        }
    }

私が逆シリアル化しようとしている XML (VS でデバッグするときに CreateAlbumFromXMLDoc メソッドに渡される Xml Doc オブジェクトからコピーされます):

<?xml version="1.0" encoding="UTF-8"?>
<photos_GetAlbums_response xsi:schemaLocation="http://api.example.com/1.0/ http://api.example.com/1.0/xxx.xsd" list="true">
<album>
 <aid>3231990241086938677</aid>
 <cover_pid>7031990241087042549</cover_pid>
 <owner>1337262814</owner>
 <name>LA</name>
 <created>1233469624</created>
 <modified>1233469942</modified>
 <description>trip to LA</description>
 <location>CA</location>
 <link>http://www.example.com/album.php?aid=7333&id=1337262814</link>
 <size>48</size>
 <visible>friends</visible>
 </album>
<album>
 <aid>7031990241086936240</aid>
 <cover_pid>7031990241087005994</cover_pid>
 <owner>1337262814</owner>
 <name>Wall Photos</name>
 <created>1230437805</created>
 <modified>1233460690</modified>
 <description/>
 <location/>
 <link>http://www.example.com/album.php?aid=3296&id=1337262814</link>
 <size>34</size>
 <visible>everyone</visible>
 </album>
<album>
 <aid>7031990241086937544</aid>
 <cover_pid>7031990241087026027</cover_pid>
 <owner>1337262814</owner>
 <name>Mobile Uploads</name>
 <created>1231984989</created>
 <modified>1233460349</modified>
 <description/>
 <location/>
 <link>http://www.example.com/album.php?aid=6300&id=1337262814</link>
 <size>3</size>
 <visible>friends</visible>
 </album>
<album>
 <aid>7031990241086936188</aid>
 <cover_pid>7031990241087005114</cover_pid>
 <owner>1337262814</owner>
 <name>Christmas 2008</name>
 <created>1230361978</created>
 <modified>1230362306</modified>
 <description>My Album</description>
 <location/>
 <link>http://www.example.com/album.php?aid=5234&id=1337262814</link>
 <size>50</size>
 <visible>friends</visible>
 </album>
<album>
 <aid>7031990241086935881</aid>
 <cover_pid>7031990241087001093</cover_pid>
 <owner>1637262814</owner>
 <name>Hock</name>
 <created>1229889219</created>
 <modified>1229889235</modified>
 <description>Misc Pics</description>
 <location/>
 <link>http://www.example.com/album.php?aid=4937&id=1637262814</link>
 <size>1</size>
 <visible>friends-of-friends</visible>
 </album>
<album>
 <aid>7031990241086935541</aid>
 <cover_pid>7031990241086996817</cover_pid>
 <owner>1637262814</owner>
 <name>Test Album 2 (for work)</name>
 <created>1229460455</created>
 <modified>1229460475</modified>
 <description>this is a test album</description>
 <location/>
 <link>http://www.example.com/album.php?aid=4547&id=1637262814</link>
 <size>1</size>
 <visible>everyone</visible>
 </album>
<album>
 <aid>7031990241086935537</aid>
 <cover_pid>7031990241086996795</cover_pid>
 <owner>1637262814</owner>
 <name>Test Album (for work)</name>
 <created>1229459168</created>
 <modified>1229459185</modified>
 <description>Testing for work</description>
 <location/>
 <link>http://www.example.com/album.php?aid=4493&id=1637262814</link>
 <size>1</size>
 <visible>friends</visible>
 </album>
 </photos_GetAlbums_response>

補足:念のため、その XML を XML Notepad 2007 に貼り付けると、次のように表示されます。

XML ドキュメントに xml-stylesheet 処理命令が含まれていません。XSLT 変換を提供するには、ファイルの先頭に次を追加し、それに応じて href 属性を編集します。

それは、それが不正な形式であることを意味するのではなく、注意すべきことだと思います。

そう..

私の最終的な目標は、このいまいましいエラーを明らかにパスし、エラーを乗り越えることができたら、上記のコードを使用してアルバムの配列を取得することです。また、Album クラスの Album[] プロパティ、またはここで不足している可能性のあるものを使用して、アルバムの配列を取得しようとする際に、コードが正しいことを確認したいと思います。私はそれがかなり近いと思うし、うまくいくはずですが、そうではありません。


ファローアップ。それ以来ずっと髪を伸ばしています。

これが最新です。Enum などの (Marc からの) 今のところ使用していないものもあります。後で変更する可能性があります。奇妙に見えたので、日時のものも引き出しましたが、それなしではエラーは発生しませんでした...少なくともまだ。現在の主な問題は、いまいましい XML です。

私が推測するフォーマットにまだ問題があるように見えますか?別の問題を隠蔽しない限り、手がかりはありません。これは私を夢中にさせています。

逆シリアル化が開始されると、次のエラーが発生します

Data at the root level is invalid. Line 1, position 1.

コードの次の行でエラーが発生します: GetAlbumsResponse album = (GetAlbumsResponse)serializer.Deserialize(reader);

XmL doc への応答を取得する方法:

public static XmlDocument GetResponseXmlDocument(HttpWebResponse response)
        {
            Stream dataStream = null; // stream from WebResponse
            XmlDocument doc = new XmlDocument();

            if (doc == null)
            {
                throw new NullReferenceException("The web reponse was null");
            }

            // Get the response stream so we can read the body of the response
            dataStream = response.GetResponseStream();

            // Open the stream using a StreamReader for easy access
            StreamReader reader = new StreamReader(dataStream);

            // Load response into string variable so that we can then load into an XML doc
            string responseString = reader.ReadToEnd();

            // Create an XML document & load it with the response data
            doc.LoadXml(responseString);

            // Final XML document that represents the response
            return doc;
        }

マイ アルバム クラスとルート レベル クラス(Marc のおかげで..今すぐ取得できます):

namespace xxx.Entities
{

    [Serializable, XmlRoot("photos_GetAlbums_response")]
    public class GetAlbumsResponse
    {
        [XmlElement("album")]
        public List<Album> Albums { get; set; }

        [XmlAttribute("list")]
        public bool IsList { get; set; }
    }

    public class Album
    {
        #region Constructors

        public Album()
        {

        }

        #endregion

        #region ElementConstants

        /// <summary>
        /// Constants Class to eliminate use of Magic Strings (hard coded strings)
        /// </summary>
        public static class ElementConstants
        {
            public const string aID = "aid";
            public const string Owner = "owner";
            public const string AlbumName = "name";
            public const string CoverPhotoID = "cover_pid";
            public const string CreateDate = "created";
            public const string LastModifiedDate = "modified";
            public const string Description = "description";
            public const string Location = "location";
            public const string AlbumURL = "link";
            public const string Size = "size";
            public const string Visible = "visible";
        }

        #endregion ElementConstants

        #region Public Properties

        [XmlElement (ElementName = ElementConstants.aID, DataType = "string")]
        public string AlbumID { get; set; }

        [XmlElement(ElementName = ElementConstants.CoverPhotoID, DataType = "int")]
        public Int32 CoverPhotoID { get; set; }

        [XmlElement(ElementName = ElementConstants.Owner, DataType = "string")]
        public string Owner { get; set; }

        [XmlElement(ElementName = ElementConstants.AlbumName, DataType = "string")]
        public string AlbumName { get; set; }

        public string Created { get; set; }

        public DateTime Modified { get; set; }

        [XmlElement(ElementName = ElementConstants.Description, DataType = "string")]
        public string Description { get; set; }

        [XmlElement(ElementName = ElementConstants.Location, DataType = "string")]
        public string Location { get; set; }

        [XmlElement(ElementName = ElementConstants.AlbumURL, DataType = "string")]
        public string Link { get; set; }

        public string Size { get; set; }

        [XmlElement(ElementName = ElementConstants.Visible, DataType = "string")]
        public string Visible { get; set; }

        #endregion
    }
}

私のシリアライザクラス:

namespace xxx.Utilities
{
    public class Serializer
    {
        public static List<Album> CreateAlbumFromXMLDoc(XmlDocument doc)
        {
            // Create an instance of a serializer
            var serializer = new XmlSerializer(typeof(Album));
            var reader = new StringReader(doc.ToString());

            // Deserialize the Xml Object and cast to type Album
            GetAlbumsResponse album = (GetAlbumsResponse)serializer.Deserialize(reader);

            return album.Albums;
        }
    }
}

私がデシリアライズしようとしている真のXML着信(はい、xmlnsがあります):

<?xml version="1.0" encoding="UTF-8"?>
<photos_GetAlbums_response xmlns="http://api.example.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.example.com/1.0/ http://api.example.com/1.0/xxx.xsd" list="true">
  <album>
    <aid>7321990241086938677</aid>
    <cover_pid>7031990241087042549</cover_pid>
    <owner>1124262814</owner>
    <name>Album Test 1</name>
    <created>1233469624</created>
    <modified>1233469942</modified>
    <description>Our trip</description>
    <location>CA</location>
    <link>http://www.example.com/album.php?aid=7733&id=1124262814</link>
    <size>48</size>
    <visible>friends</visible>
  </album>
  <album>
    <aid>231990241086936240</aid>
    <cover_pid>7042330241087005994</cover_pid>
    <owner>1124262814</owner>
    <name>Album Test 2</name>
    <created>1230437805</created>
    <modified>1233460690</modified>
    <description />
    <location />
    <link>http://www.example.com/album.php?aid=5296&id=1124262814</link>
    <size>34</size>
    <visible>everyone</visible>
  </album>
  <album>
    <aid>70319423341086937544</aid>
    <cover_pid>7032390241087026027</cover_pid>
    <owner>1124262814</owner>
    <name>Album Test 3</name>
    <created>1231984989</created>
    <modified>1233460349</modified>
    <description />
    <location />
    <link>http://www.example.com/album.php?aid=6600&id=1124262814</link>
    <size>3</size>
    <visible>friends</visible>
  </album>
</photos_GetAlbums_response>
4

9 に答える 9

5

個人的には、ここでは定数を使用しません。エラーを見つけるのが難しくなります (おそらく定数を再利用しないので、あまり追加しないでください)。例えば:

    [XmlElement (ElementName = ElementConstants.AlbumName, DataType = "string")]
    public string AlbumID { get; set; }
...
    [XmlElement(ElementName = ElementConstants.AlbumName, DataType = "string")]
    public string AlbumName { get; set; }

私には疑わしいように見えます...

より簡単な方法は、必要な xml をファイル ( など) に書き込み、次foo.xmlを使用することです。

xsd foo.xml
xsd foo.xsd /classes

次に を見てくださいfoo.cs

于 2009-02-07T08:53:15.880 に答える
3

では、xml が無効であることに注意してください (宣言されていない名前空間エイリアスを使用する&必要があります)。また、可視性のための列挙型を追加し、long を に変換するための処理を追加し、ラッパー タイプを追加したことにも注意してください。&amp;xsiDateTime

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

static class Program
{
    const string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<photos_GetAlbums_response
    xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
    xsi:schemaLocation=""http://api.example.com/1.0/ http://api.example.com/1.0/xxx.xsd""
    list=""true"">
<album>
 <aid>3231990241086938677</aid>
 <cover_pid>7031990241087042549</cover_pid>
 <owner>1337262814</owner>
 <name>LA</name>
 <created>1233469624</created>
 <modified>1233469942</modified>
 <description>trip to LA</description>
 <location>CA</location>
 <link>http://www.example.com/album.php?aid=7333&amp;id=1337262814</link>
 <size>48</size>
 <visible>friends</visible>
 </album>
<album>
 <aid>7031990241086936240</aid>
 <cover_pid>7031990241087005994</cover_pid>
 <owner>1337262814</owner>
 <name>Wall Photos</name>
 <created>1230437805</created>
 <modified>1233460690</modified>
 <description/>
 <location/>
 <link>http://www.example.com/album.php?aid=3296&amp;id=1337262814</link>
 <size>34</size>
 <visible>everyone</visible>
 </album>
<album>
 <aid>7031990241086937544</aid>
 <cover_pid>7031990241087026027</cover_pid>
 <owner>1337262814</owner>
 <name>Mobile Uploads</name>
 <created>1231984989</created>
 <modified>1233460349</modified>
 <description/>
 <location/>
 <link>http://www.example.com/album.php?aid=6300&amp;id=1337262814</link>
 <size>3</size>
 <visible>friends</visible>
 </album>
<album>
 <aid>7031990241086936188</aid>
 <cover_pid>7031990241087005114</cover_pid>
 <owner>1337262814</owner>
 <name>Christmas 2008</name>
 <created>1230361978</created>
 <modified>1230362306</modified>
 <description>My Album</description>
 <location/>
 <link>http://www.example.com/album.php?aid=5234&amp;id=1337262814</link>
 <size>50</size>
 <visible>friends</visible>
 </album>
<album>
 <aid>7031990241086935881</aid>
 <cover_pid>7031990241087001093</cover_pid>
 <owner>1637262814</owner>
 <name>Hock</name>
 <created>1229889219</created>
 <modified>1229889235</modified>
 <description>Misc Pics</description>
 <location/>
 <link>http://www.example.com/album.php?aid=4937&amp;id=1637262814</link>
 <size>1</size>
 <visible>friends-of-friends</visible>
 </album>
<album>
 <aid>7031990241086935541</aid>
 <cover_pid>7031990241086996817</cover_pid>
 <owner>1637262814</owner>
 <name>Test Album 2 (for work)</name>
 <created>1229460455</created>
 <modified>1229460475</modified>
 <description>this is a test album</description>
 <location/>
 <link>http://www.example.com/album.php?aid=4547&amp;id=1637262814</link>
 <size>1</size>
 <visible>everyone</visible>
 </album>
<album>
 <aid>7031990241086935537</aid>
 <cover_pid>7031990241086996795</cover_pid>
 <owner>1637262814</owner>
 <name>Test Album (for work)</name>
 <created>1229459168</created>
 <modified>1229459185</modified>
 <description>Testing for work</description>
 <location/>
 <link>http://www.example.com/album.php?aid=4493&amp;id=1637262814</link>
 <size>1</size>
 <visible>friends</visible>
 </album>
 </photos_GetAlbums_response>";
    static void Main()
    {
        XmlSerializer ser = new XmlSerializer(typeof(GetAlbumsResponse));
        GetAlbumsResponse response;
        using (StringReader reader = new StringReader(xml))
        {
            response = (GetAlbumsResponse)ser.Deserialize(reader);
        }

    }
}

[Serializable, XmlRoot("photos_GetAlbums_response")]
public class GetAlbumsResponse
{
    [XmlElement("album")]
    public List<Album> Albums {get;set;}

    [XmlAttribute("list")]
    public bool IsList { get; set; }
}
public enum AlbumVisibility
{
    [XmlEnum("")]
    None,
    [XmlEnum("friends")]
    Friends,
    [XmlEnum("friends-of-friends")]
    FriendsOfFriends,
    [XmlEnum("everyone")]
    Everyone

}
[Serializable]
public class Album
{
    static readonly DateTime epoch = new DateTime(1970, 1, 1);
    static long SerializeDateTime(DateTime value)
    {
        return (long)((value - epoch).TotalSeconds);
    }
    static DateTime DeserializeDateTime(long value)
    {
        return epoch.AddSeconds(value);
    }
    [XmlElement("aid")]
    public long AlbumID { get; set; }

    [XmlElement("cover_pid")]
    public long CoverPhotoID { get; set; }

    [XmlElement("owner")]
    public long Owner { get; set; }

    [XmlElement("name")]
    public string AlbumName { get; set; }

    [XmlIgnore]
    public DateTime CreateDate { get; set; }

    [XmlElement("created"), Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public long CreateDateInt64 {
        get {return SerializeDateTime(CreateDate);}
        set {CreateDate = DeserializeDateTime(value);}
    }

    [XmlIgnore]
    public DateTime LastModifiedDate { get; set; }

    [XmlElement("modified"), Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public long LastModifiedDateInt64
    {
        get { return SerializeDateTime(LastModifiedDate); }
        set { LastModifiedDate = DeserializeDateTime(value); }
    }

    [XmlElement("description")]
    public string Description { get; set; }

    [XmlElement("location")]
    public string Location { get; set; }

    [XmlElement("link")]
    public string Link { get; set; }

    [XmlElement("size")]
    public int Size { get; set; }

    [XmlElement("visible")]
    public AlbumVisibility Visibility { get; set; }
}
于 2009-02-07T09:22:10.113 に答える
2

(2 月 8 日) まず、xml を (読み取り用の) 文字列として扱ってもエラーは発生しません。

問題は名前空間 (xmlns なしxsi) です。これは以前のxmlにはなかったので、含めることができませんでした...基本的に、シリアライザーにそれについて伝える必要があります:

[Serializable, XmlRoot("photos_GetAlbums_response",
    Namespace="http://api.example.com/1.0/")]
public class GetAlbumsResponse { /* code as before */ }

[Serializable, XmlType(Namespace="http://api.example.com/1.0/")]
public class Album { /* code as before */ }

この場合、名前空間の定数はにかなっています (再利用しているため)。

表示している xml が正確な場合でも、リンクはまだ壊れています...しかし、これは単なるコピー/貼り付けである可能性があります (つまり、エラーであることがわかるまで、この変更を適用しないでください...) &amp;: &)。いくつかの「置換」を提案します...最も粗いレベルで:

string fixedXml = xml.Replace("&", "&amp;");

(ただし、より正確なものの方が良い場合があります-おそらく正規表現)

異なるデータを使用して、(長いのではなく) いくつかのデータ文字列も作成する必要があることに注意してください。

[XmlElement("aid")]
public string AlbumID { get; set; }

[XmlElement("cover_pid")]
public string CoverPhotoID { get; set; }

[XmlElement("owner")]
public string Owner { get; set; }

これらの変更 (およびほとんどが私の元のコード) により、動作します。

もちろん、この時点で「 xsd を使えばよかった」と思うはずです。

于 2009-02-08T10:33:08.783 に答える
1

現在のコードで機能する Xml は次のようなものです。

<Album><photos_GetAlbums_response>
<Album>
   <photos_GetAlbums_response>
      <Album>
         <photos_GetAlbums_response> ....

アルバムの配列を持つレスポンス。各アルバムにはアルバムの配列であるレスポンスがあります...など。

とにかく、私はすでにあなたの他の質問を手伝い、完全に機能するコードサンプルを作成するのに苦労しました. 同じ問題に対して別の質問を作成したのはなぜですか?

于 2009-02-07T17:51:12.347 に答える
1

良い、

問題を対象とした Microsoft からのリンクがあります

于 2009-02-06T04:40:34.363 に答える
1

はい - アルバムは間違いなく XML のルート ノードではありません。

アルバムのリストを含む GetAlbumsResponse クラスを作成し、逆シリアル化コードをラッパー クラスに移動することをお勧めします。

基本的に、Album クラス定義からルート要素を削除し、次のようにします。

  [XmlRoot (ElementName="GetAlbums_response")]
public class GetAlbumsResponse
{
    #region Constructors

    public GetAlbumsResponse()
    {

    }

    #endregion



    [XmlArray(ElementName="album")]
    public List<Album> Albums{get;set;}

    ... deserialization code...

}

于 2009-02-06T04:42:56.947 に答える
1

わかりました-例をコーディングしました。私は Facebook API を調べましたが、ここに完全な動作例があります。これを試して:

[XmlRoot("photos_getAlbums_response", Namespace="http://api.facebook.com/1.0/")]
public class GetAlbumsResponse
{
    public GetAlbumsResponse() 
    {    
    }

    [XmlElement("album")]
    public List<Album> Albums { get; set; }
}

public class Album
{
    [XmlElement("aid")]
    public long Aid{get;set;}

    [XmlElement("cover_pid")]
    public long CoverPid{get;set;}

    [XmlElement("owner")]
    public long Owner{get;set;}

    [XmlElement("name")]
    public string Name{get;set;}

    [XmlElement("created")]
    public long Created{get;set;}

    [XmlElement("modified")]
    public long Modified{get;set;}

    [XmlElement("description")]
    public string Description{get;set;}

    [XmlElement("location")]
    public string Location{get;set;}

    [XmlElement("link")]
    public string Link{get;set;}

    [XmlElement("size")]
    public int Size{get;set;}

    [XmlElement("visible")]
    public string Visible{get;set;}

    public Album()
    {}
}

class XmlUtils
{
    public static T DeserializeFromXml<T>(string xml)
    {
        T result;
        XmlSerializer ser = new XmlSerializer(typeof(T));
        using (TextReader tr = new StringReader(xml))
        {
            result = (T)ser.Deserialize(tr);
        }
        return result;
    }
}

今.. Facebook API からの xml photos_getAlbums_response を使用して、

次のように逆シリアル化できます。

 GetAlbumsResponse response = XmlUtils.DeserializeFromXml<GetAlbumsResponse>(xmlResponseString);
于 2009-02-06T05:29:55.603 に答える
1

System.Xml.XmlDocument を使用して入力を解析します。 自分でデータを抽出するコードを書くのに 1 時間以上かかることはありません。

于 2009-02-08T06:20:20.823 に答える