0

次の形式のxmlがあります

<?xml version="1.0" ?>
<manifest attr="TEXT" attr="TEXT" attr="TEXT">
<list name="TRIM">
    <feature id="TEXT"/>
    <feature id="TEXT"/>
    <feature id="TEXT"/>
    <feature id="TEXT"/>
    <feature id="TEXT"/>
</list>
<list attr="TEXT">
    <feature id="TEXT"/>
    <feature id="TEXT"/>
</list>
<list attr="TEXT"/>
<list attr="TEXT">
    <feature id="TEXT" attr="TEXT"/>
    <feature id="TEXT" attr="TEXT"/>
</list>
</manifest>

C# と IXmlSerializable インターフェイスを使用してこれをシリアル化しようとしています。私は 3 つのクラスを持っています。これらはすべてインターフェイス IXmlSerializable を継承しています。私の意図は、XML が最上位のクラスによって読み込まれ、型「リスト」の xml を子オブジェクト シリアライザーに渡すことをループすることです。次に、「リスト」シリアライズは、すべての「機能」エントリをループします。以下は私のコードの縮小版です。

私はループに対していくつかのアプローチを試みましたが、常に無限ループ、間違ったタイプの xml の間違ったビットをシリアライズしようとすることによるエラー、またはリスト全体をスキップした後に最後に到達することになります。

私は Xml シリアライゼーションが初めてで、このアプローチはナイーブです。提案を喜んで受け入れます。

この XML は将来 (より多くの属性、要素の種類など) 変更される可能性が高いため、保守可能である必要があります。空の要素が存在しないことも保証できません。

using UnityEngine;
using System.Collections;
using System.Xml.Serialization;

[XmlRoot("partManifest")]
public class ModelManifest : IEnumerator, IEnumerable, IXmlSerializable {

    [XmlRoot("feature")]
    public class Feature : IXmlSerializable
    {
        string m_id;
        string m_description;

        #region IXmlSerializable implementation
        System.Xml.Schema.XmlSchema System.Xml.Serialization.IXmlSerializable.GetSchema ()    
        {
            throw new System.NotImplementedException ();
        }

        void System.Xml.Serialization.IXmlSerializable.ReadXml (System.Xml.XmlReader reader)
        {       
        m_id = reader.GetAttribute("id");
        }

        void System.Xml.Serialization.IXmlSerializable.WriteXml (System.Xml.XmlWriter writer)
        {
        throw new System.NotImplementedException ();
        }
        #endregion
    }

    [XmlRoot("feature-list")]
    public class FeatureList : IXmlSerializable
    {
        string m_name;

        System.Collections.Generic.List<Feature> m_features = new System.Collections.Generic.List<Feature>();

        #region IXmlSerializable implementation
        public System.Xml.Schema.XmlSchema GetSchema ()
        {
            throw new System.NotImplementedException ();
        }

        public void ReadXml (System.Xml.XmlReader reader)
        {               
            XmlSerializer valueSerializer = new XmlSerializer(typeof(Feature));

            // Will return if no features present
            if(reader.IsEmptyElement)
                return;

            reader.ReadStartElement("feature-list");
            while(true)
            {
                m_features.Add ( (Feature)valueSerializer.Deserialize(reader) );
                i++;
                bool l_isAnotherSibling = reader.ReadToNextSibling("feature");

                if(!l_isAnotherSibling)
                    break;
            }
            Debug.Log (i.ToString() + " Features");
        }

        public void WriteXml (System.Xml.XmlWriter writer)
        {
            throw new System.NotImplementedException ();
        }
        #endregion
    }

    System.Collections.Generic.List<FeatureList> m_featureLists = new System.Collections.Generic.List<FeatureList>();

    #region IXmlSerializable implementation
    public System.Xml.Schema.XmlSchema GetSchema ()
    {
        throw new System.NotImplementedException ();
    }

    public void ReadXml (System.Xml.XmlReader reader)
    {       
        XmlSerializer valueSerializer = new XmlSerializer(typeof(FeatureList));

        if(reader.IsEmptyElement)
            return;

        reader.ReadStartElement("partManifest");

        while (true)
        {               
            m_featureLists.Add ( (FeatureList)valueSerializer.Deserialize(reader) );

            //bool l_isAnotherSibling = reader.ReadToNextSibling("feature-list");

            //if(!l_isAnotherSibling)
            //  break;
            if(reader.NodeType == System.Xml.XmlNodeType.EndElement)
                break;

            if(Input.GetKeyUp(KeyCode.A))
                break;
        }

        reader.ReadEndElement();
    }

    public void WriteXml (System.Xml.XmlWriter writer)
    {
        throw new System.NotImplementedException ();
    }
    #endregion
}
4

1 に答える 1

2

IXmlSerializable を実装する必要がある本当に正当な理由がない限り、私は XmlSerializer とクラスの適切な属性を使用します。

与えられた XML の例に基づいて、これでうまくいくはずです。同じ名前の複数の属性を持つことは無効であるため、マニフェストの attr 属性の 2 つの名前を変更する必要があったことに注意してください。

using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

[Serializable]
[XmlRoot("manifest")]
public class Manifest
{
    [XmlElement("list")]
    public List<FeatureList> FeatureLists { get; set; }

    [XmlAttribute("attr")]
    public string Attr { get; set; }

    [XmlAttribute("attr2")]
    public string Attr2 { get; set; }

    [XmlAttribute("attr3")]
    public string Attr3 { get; set; }
}

[Serializable]
public class FeatureList
{
    [XmlElement("feature")]
    public List<Feature> Features { get; set; }

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

    [XmlAttribute("attr")]
    public string Attr { get; set; }
}

[Serializable]
public class Feature
{
    [XmlAttribute("id")]
    public string Id { get; set; }

    [XmlAttribute("attr")]
    public string Attr { get; set; }
}

次のようなコードを使用します。

var stream = ... // open the XML
var serializer = new XmlSerializer(typeof (Manifest));
var manifest = (Manifest) serializer.Deserialize(stream);
于 2013-07-18T17:41:45.137 に答える