名前空間によってバージョン管理されている場合、XMLを適切なオブジェクトにシリアル化する最良の方法は何ですか?

StackOverflow https://stackoverflow.com/questions/209502

質問

私の質問は次のとおりです。

名前空間によってバージョン管理されているxmlがあります。この受け取ったxmlを適切なオブジェクトにシリアル化したいのですが、これを行う唯一の方法は、xmlを2回処理する必要があることを意味します。最初に名前空間を検出し、次に検出された名前空間に基づいて適切なタイプのオブジェクトにシリアル化するため。これは非常に効率が悪いようです。ジェネリックまたは何かを使用して、「if namespace == x then serialze to」チェックなしで適切なタイプのオブジェクトを取得する方法が必要です。

以下は、これを実現する唯一の方法のサンプルです。より良いまたはより効率的な方法はありますか?

ありがとう

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace TestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod3()
        {
            //Build up an employee object to xml
            Schema.v2.Employee employee = new Schema.v2.Employee { FirstName = "First", LastName = "Last" };
            string xml = employee.ObjectToXml<Schema.v2.Employee>();

            //Now pretend I don't know what type I am receiving.
            string nameSpace = GetNamespace(xml);
            Object newemp;
            if (nameSpace == "Employee.v2")
                newemp = XmlSerializationExtension.XmlToObject<Schema.v2.Employee>(null, xml);
            else
                newemp = XmlSerializationExtension.XmlToObject<Schema.v1.Employee>(null, xml);

            // Check to make sure that the type I got was what I made.
            Assert.AreEqual(typeof(Schema.v2.Employee), newemp.GetType());
        }

        public string GetNamespace(string s)
        {
            XDocument z = XDocument.Parse(s);
            var result = z.Root.Attributes().
                    Where(a => a.IsNamespaceDeclaration).
                    GroupBy(a => a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName,
                            a => XNamespace.Get(a.Value)).
                    ToDictionary(g => g.Key,
                                 g => g.First());

            foreach (System.Xml.Linq.XNamespace item in result.Values)
                if (item.NamespaceName.Contains("Employee")) return item.NamespaceName;

            return String.Empty;
        }
    }

    public static class XmlSerializationExtension
    {
        public static string ObjectToXml<T>(this T Object)
        {
            XmlSerializer s = new XmlSerializer(Object.GetType());
            using (StringWriter writer = new StringWriter())
            {
                s.Serialize(writer, Object);
                return writer.ToString();
            }
        }
        public static T XmlToObject<T>(this T Object, string xml)
        {
            XmlSerializer s = new XmlSerializer(typeof(T));
            using (StringReader reader = new StringReader(xml))
            {
                object obj = s.Deserialize(reader);
                return (T)obj;
            }
        }
    } 
}

namespace Schema.v1
{
    [XmlRoot(ElementName = "Employee", Namespace= "Employee.v1", IsNullable = false)]
    public class Employee
    {
        [XmlElement(ElementName = "FirstName")]
        public string FirstName { get; set; }
        [XmlElement(ElementName = "LastName")]
        public string LastName { get; set; }
    }
}
namespace Schema.v2
{
    [XmlRoot(ElementName = "Employee", Namespace = "Employee.v2", IsNullable = false)]
    public class Employee
    {
        [XmlAttribute(AttributeName = "FirstName")]
        public string FirstName { get; set; }
        [XmlAttribute(AttributeName = "LastName")]
        public string LastName { get; set; }
    }
}
役に立ちましたか?

解決

2つの提案:

最初に、多分それをしないでください。シリアライズする場合は、呼び出し元がスキーマを指定しない限り、あるメソッドを他のメソッドよりも優先します。

第二に、発見のためにXMLを解析しないでください。 &quot; Employee.v2&quot;で文字列のマッチングを行うだけですおよび&quot; Employee.v1&quot; (たとえば)ファイルの最初の100バイト以内(または、どこまで情報を取得する必要があるか)。データ内で一般的な文字列にならない限り、それは機能するはずです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top