xml 역직렬화 문제

xml → object를 하기 위해서 작업을 하고 있습니다.

xml형식에 맞춰서

class Base
{

}
class A : Base
{

}

이런식으로 xml을 A class에 맞춰서 값을 뽑아내는거는 완료하였습니다.

여기서
class B: A, IFCTest
{
//기능 구현
}
xml → class B로 선언하는게 안되더라고요.
class B로 역직렬화를 할려고하면
Class A’ 형식 개체를 ‘Class B’ 형식으로 캐스팅할 수 없습니다.’ 라고 오류가 나옵니다…
class B에는 그냥 상속만 받은 상태나, 인터페이스 상속없이 진행해도 다음과 같이 나오더라고요… 이유를 모르겠습니다.

XML Deserialize시

엘리먼트 이름을 기준으로 클래스 이름을 유추하여 매칭 시킵니다.

아마 class A Serialize시
<A xmlns:xsi=…
형식으로 xml문자가 만들어 졌을텐데요

위 A엘리먼트 이름과 Deserialize 대상의 class B의 이름 매칭이 맞지 않아 오류가 난 것으로 판단됩니다.

이럴땐 class에 xmlRoot어트리뷰트를 씌워서 엘리먼트 이름을 공통화 시키면 가능합니다.

public class Base
{
        public string BaseValue { get; set; }
}

[XmlRoot(Namespace = "foo", ElementName = "RootElement", DataType = "string", IsNullable = true)]
public class A : Base
{
        public string AValue { get; set; }
}

[XmlRoot(Namespace = "foo", ElementName = "RootElement", DataType = "string", IsNullable = true)]
public class B : Base
{
        public string AValue { get; set; }
        public string BValue { get; set; }
}
3 Likes

직렬화를 한번 하고 B로 역직렬화를 진행해야 하지 않나요?

2 Likes

앗 감사합니다 이방식대로 한번 진행해보겠습니다

1 Like

b로 역직렬화가 안되더라고요. ㅠㅠ 아마 앨리먼트 관련해서 설정을 안해줘서 그런거같습니다 ㅠ

1 Like

아 다시 보니깐 제가 질문드린 내용은

public class Base
{
    public string BaseValue { get; set; }
}

[XmlRoot(Namespace = "foo", ElementName = "RootElement", DataType = "string", IsNullable = true)]
public class A : Base
{
    public string AValue { get; set; }
}

[XmlRoot(Namespace = "foo", ElementName = "RootElement", DataType = "string", IsNullable = true)]
public class B : A
{
    public string AValue { get; set; }
    public string BValue { get; set; }
}

에서 Class A는 xml Deserialize가 진행되는데 B가 진행이 안되는 경우입니다 ㅠㅠ

1 Like

저는 잘 되는데 안되는 코드를 올려주시겠어요?

참고로 제가 해본 코드 입니다.

public class Base
{
        public string BaseValue { get; set; }
}

[XmlRoot(Namespace = "foo", ElementName = "RootElement", DataType = "string", IsNullable = true)]
public class A : Base
{
        public string AValue { get; set; }
}

[XmlRoot(Namespace = "foo", ElementName = "RootElement", DataType = "string", IsNullable = true)]
public class B : Base
{
        public string AValue { get; set; }
        public string BValue { get; set; }
}

직렬화

B b = new B();
b.BaseValue = "BaseValue";
b.AValue = "AValue";
b.BValue = "BValue";

// B클래스 시리얼라이즈
XmlSerializer serializer = new XmlSerializer(typeof(B));
string xmlData;
using (MemoryStream memStream = new MemoryStream())
{
                // 네임스페이스 제거
                var xns = new XmlSerializerNamespaces();
                xns.Add(string.Empty, string.Empty);

                XmlWriterSettings settings = new XmlWriterSettings
                {
                    Indent = true,
                    IndentChars = new string(' ', 4),
                    NewLineOnAttributes = false,
                    Encoding = Encoding.UTF8
                };

                using (XmlWriter xmlWriter = XmlWriter.Create(memStream, settings))
                {
                    serializer.Serialize(xmlWriter, b, xns);
                }

                xmlData = Encoding.UTF8.GetString(memStream.GetBuffer());
                xmlData = xmlData.Substring(xmlData.IndexOf('<'));
                xmlData = xmlData.Substring(0, xmlData.LastIndexOf('>') + 1);
}

역직렬화

B bb = null;
using (StringReader stringReader = new StringReader(xmlData))
{
                using (XmlTextReader xmlReader = new XmlTextReader(stringReader))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(B));
                    bb = serializer.Deserialize(xmlReader) as B;
                }
}
2 Likes

직렬화 코드를… 왜 그렇게 복잡하게 만드신 것인지 혹시 이유를 알 수 있을까요? 아마도 BOM 때문인 것 같은데, 그냥 다음과 같이 직렬화/역직렬화를 하시면 됩니다.

string xmlData;

        {
            B b = new B();
            b.BaseValue = "BaseValue";
            b.AValue = "AValue";
            b.BValue = "BValue";

            XmlSerializer serializer = new XmlSerializer(typeof(B));
            using (MemoryStream memStream = new MemoryStream())
            {
                XmlWriterSettings settings = new XmlWriterSettings
                {
                    Encoding = new UTF8Encoding(false)
                };

                using (XmlWriter xmlWriter = XmlWriter.Create(memStream, settings))
                {
                    serializer.Serialize(xmlWriter, b);
                }

                xmlData = Encoding.UTF8.GetString(memStream.GetBuffer());
            }
        }

        {
            B bb = null;
            using (StringReader stringReader = new StringReader(xmlData))
            {
                using (XmlTextReader xmlReader = new XmlTextReader(stringReader))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(B));

                    bb = serializer.Deserialize(xmlReader) as B;
                }
            }
        }

그리고 위의 답변은 질문과는 무관한 듯합니다. 답변의 직렬화/역직렬화는 단순히 XmlRoot 특성을 지정하지 않아도 잘 되는 유형입니다.

사실 이 문제가 이렇게 복잡해진 것은 질문자가 재현 가능한 예제 코드를 싣지 않아서입니다. 이 정도의 설명만으로는 질문자가 뭘 원하는 것인지 알 수가 없습니다. 즉, 상상해서 답변할 여지가 너무 많습니다.

4 Likes

@aroooong @kevin13 답변 감사합니다 저도 코드를 올리고싶은데 따로 프로젝트라 올릴수가 없는게 아쉽네요
저는 단순히 Class A를 b에다가 상속을 하였을뿐인데 A 역직렬화는 잘되는데 안되는 이유가 상속이랑 직렬화랑 문제가 있나 했습니다 좀더 공부해야될것같네요 ㅎㅎ 답변 다시한번 감사합니다!

2 Likes