XmlSerializer를 사용하여 빈 xml 특성 값을 nullable int 속성으로 역직렬화
제가 서드파티에서 xml을 받아서 C# 객체로 역직렬화해야 합니다.이 xml에는 정수 형식 또는 빈 값의 특성(attr="11" 또는 attr="")이 포함될 수 있습니다.이 속성 값을 nullable 정수 유형의 속성으로 역직렬화하고 싶습니다.그러나 XmlSerializer는 nullable 유형으로의 역직렬화를 지원하지 않습니다.InvalidOperation으로 XmlSerializer를 생성하는 동안 다음 테스트 코드가 실패함예외 {"'TestConsoleApplication' 유형을 반영하는 동안 오류가 발생했습니다.serialize Me'."}
[XmlRoot("root")]
public class SerializeMe
{
[XmlElement("element")]
public Element Element { get; set; }
}
public class Element
{
[XmlAttribute("attr")]
public int? Value { get; set; }
}
class Program {
static void Main(string[] args) {
string xml = "<root><element attr=''>valE</element></root>";
var deserializer = new XmlSerializer(typeof(SerializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (SerializeMe)deserializer.Deserialize(xmlStream);
}
}
'Value' 속성 유형을 int로 변경하면 InvalidOperation과 함께 역직렬화가 실패함예외:
XML 문서 (1, 16)에 오류가 있습니다.
비어 있지 않은 속성 값을 정수로 병렬화함과 동시에 null로 병렬화하는 방법을 조언해 줄 수 있는 사람이 있습니까?각 필드를 수동으로 역직렬화할 필요가 없도록(실제로는 많이 있음) 이에 대한 요령이 있습니까?
스틸의 코멘트 후 업데이트:
-
이 속성은 XmlElementAttribute에서만 작동하는 것으로 알고 있습니다. 이 속성은 요소에 하위 요소든 본문 텍스트든 내용이 없음을 지정합니다.하지만 XmlAttribute에 대한 해결책을 찾아야 합니다.어쨌든 저는 xml을 제어할 수 없기 때문에 변경할 수 없습니다.
-
이 속성은 특성 값이 비어 있지 않거나 특성이 없는 경우에만 작동합니다.특성에 빈 값이 있으면(attr=''') XmlSerializer 구성자가 실패합니다(예상대로).
public class Element { [XmlAttribute("attr")] public int Value { get; set; } [XmlIgnore] public bool ValueSpecified; }
Alex Scordellis의 이 블로그 게시물과 같은 Custom Nullable 클래스
저는 이 블로그 게시물의 수업을 제 문제에 적용하려고 했습니다.
[XmlAttribute("attr")] public NullableInt Value { get; set; }
그러나 XmlSerializer 구성자가 InvalidOperation과 함께 실패합니다.예외:
TestConsoleApplication 유형의 멤버 'Value'를 직렬화할 수 없습니다.널블인트.
XmlSerializable}을(를) 구현하는 유형을 인코딩하는 데 XmlAttribute/XmlText를 사용할 수 없습니다.
추악한 대리 해결책 (여기에 이 코드를 쓴 것이 부끄럽습니다 :):
public class Element { [XmlAttribute("attr")] public string SetValue { get; set; } public int? GetValue() { if ( string.IsNullOrEmpty(SetValue) || SetValue.Trim().Length <= 0 ) return null; int result; if (int.TryParse(SetValue, out result)) return result; return null; } }
하지만 저는 이런 해결책을 생각해내고 싶지 않습니다. 왜냐하면 그것은 소비자들을 위한 저희 클래스의 인터페이스를 깨뜨리기 때문입니다.IXml Serializable 인터페이스를 수동으로 구현하는 것이 좋겠습니다.
현재 전체 Element 클래스에 대해 IXml Serializable을 구현해야 할 것 같습니다(큰 규모임). 간단한 해결 방법은 없습니다.
작동해야 합니다.
[XmlIgnore]
public int? Age { get; set; }
[XmlElement("Age")]
public string AgeAsText
{
get { return (Age.HasValue) ? Age.ToString() : null; }
set { Age = !string.IsNullOrEmpty(value) ? int.Parse(value) : default(int?); }
}
IXml Serializable 인터페이스를 구현하여 이 문제를 해결하였습니다.더 쉬운 방법을 찾지 못했습니다.
테스트 코드 샘플은 다음과 같습니다.
[XmlRoot("root")]
public class DeserializeMe {
[XmlArray("elements"), XmlArrayItem("element")]
public List<Element> Element { get; set; }
}
public class Element : IXmlSerializable {
public int? Value1 { get; private set; }
public float? Value2 { get; private set; }
public void ReadXml(XmlReader reader) {
string attr1 = reader.GetAttribute("attr");
string attr2 = reader.GetAttribute("attr2");
reader.Read();
Value1 = ConvertToNullable<int>(attr1);
Value2 = ConvertToNullable<float>(attr2);
}
private static T? ConvertToNullable<T>(string inputValue) where T : struct {
if ( string.IsNullOrEmpty(inputValue) || inputValue.Trim().Length == 0 ) {
return null;
}
try {
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
return (T)conv.ConvertFrom(inputValue);
}
catch ( NotSupportedException ) {
// The conversion cannot be performed
return null;
}
}
public XmlSchema GetSchema() { return null; }
public void WriteXml(XmlWriter writer) { throw new NotImplementedException(); }
}
class TestProgram {
public static void Main(string[] args) {
string xml = @"<root><elements><element attr='11' attr2='11.3'/><element attr='' attr2=''/></elements></root>";
XmlSerializer deserializer = new XmlSerializer(typeof(DeserializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (DeserializeMe)deserializer.Deserialize(xmlStream);
}
}
저는 최근에 연재 작업을 많이 해왔고, 가치 유형에 대한 null data를 다룰 때 다음의 기사와 게시물들이 도움이 된다는 것을 알게 되었습니다.
C#에서 XmlSerializer로 값 유형을 null로 만드는 방법 - serialization에 대한 답은 XmlSerializer의 꽤 괜찮은 트릭을 자세히 설명합니다.특히 XmlSerialier는 XXXSpecified boolean 속성을 검색하여 null을 무시할 수 있는 속성을 포함해야 하는지 여부를 결정합니다.
Alex Scordellis는 StackOverflow 질문을 했고 좋은 답변을 받았습니다.Alex는 또한 자신의 블로그에 XmlSerializer를 사용하여 Nullable<int>로 역직렬화하는 문제에 대해 잘 썼습니다.
Xsi:nil 속성 바인딩 지원에 대한 MSDN 설명서도 유용합니다.IXml Serializable Interface의 설명서가 그렇듯, 구현을 직접 작성하는 것이 마지막 수단이 될 것입니다.
내 대답을 모자에 집어넣는 편이 낫겠다고 생각했습니다. IXml Serializable 인터페이스를 구현하는 사용자 지정 유형을 만들어 이 문제를 해결했습니다.
다음 노드가 있는 XML 개체가 있다고 가정합니다.
<ItemOne>10</Item2>
<ItemTwo />
이들을 표현할 개체:
public class MyItems {
[XmlElement("ItemOne")]
public int ItemOne { get; set; }
[XmlElement("ItemTwo")]
public CustomNullable<int> ItemTwo { get; set; } // will throw exception if empty element and type is int
}
변환과 함께 잠재적인 nullable 항목을 나타내는 동적 nullable structure
public struct CustomNullable<T> : IXmlSerializable where T: struct {
private T value;
private bool hasValue;
public bool HasValue {
get { return hasValue; }
}
public T Value {
get { return value; }
}
private CustomNullable(T value) {
this.hasValue = true;
this.value = value;
}
public XmlSchema GetSchema() {
return null;
}
public void ReadXml(XmlReader reader) {
string strValue = reader.ReadString();
if (String.IsNullOrEmpty(strValue)) {
this.hasValue = false;
}
else {
T convertedValue = strValue.To<T>();
this.value = convertedValue;
this.hasValue = true;
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer) {
throw new NotImplementedException();
}
public static implicit operator CustomNullable<T>(T value) {
return new CustomNullable<T>(value);
}
}
public static class ObjectExtensions {
public static T To<T>(this object value) {
Type t = typeof(T);
// Get the type that was made nullable.
Type valueType = Nullable.GetUnderlyingType(typeof(T));
if (valueType != null) {
// Nullable type.
if (value == null) {
// you may want to do something different here.
return default(T);
}
else {
// Convert to the value type.
object result = Convert.ChangeType(value, valueType);
// Cast the value type to the nullable type.
return (T)result;
}
}
else {
// Not nullable.
return (T)Convert.ChangeType(value, typeof(T));
}
}
}
로드를 통해 이 작업을 수행할 수도 있습니다.xml
의 상태가 된XmlDocument
그리고 이것을 역직렬화해서,Json
물건을 받다T
당신이 찾고 있는 것입니다.
public static T XmlToModel<T>(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
T result = JsonConvert.DeserializeObject<T>(jsonText);
return result;
}
언급URL : https://stackoverflow.com/questions/1295697/deserializing-empty-xml-attribute-value-into-nullable-int-property-using-xmlseri
'programing' 카테고리의 다른 글
WP_Query meta_query 날짜 범위(사용자 정의 필드 2개 포함) (0) | 2023.10.16 |
---|---|
j.트리거의 장점/차이 .trigger() vs.click() (0) | 2023.10.16 |
값이 숫자 범위 내에 있는지 확인합니다. (0) | 2023.10.11 |
고정 사이드바가 jQuery와 바닥글이 겹치지 않게 하려면 어떻게 해야 합니까? (0) | 2023.10.11 |
Angular에서 페이지 로드 후 앵커링하려면 스크롤 (0) | 2023.10.11 |