XmlSerializer를 사용하여 빈 xml 속성 값을 nullable int 속성으로 역화 화
xml을 가져 오기에서 C # 개체로 역화해야합니다. 이 xml은 정수 유형 값 또는 빈 값 (attr =”11”또는 attr =””)의 속성이 사용할 수 있습니다. 이 속성 값을 nullable 정수 유형의 속성으로 deserialize하고 싶습니다. 그러나 XmlSerializer는 nullable 형식으로의 역화를 지원하지 않습니다. InvalidOperationException { " 'TestConsoleApplication.SerializeMe'유형 반영 오류가 발생했습니다."}와 함께 XmlSerializer를 만드는 동안 다음 테스트 코드가 실패합니다.
[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로 변경하면 InvalidOperationException으로 deserialization이 실패합니다.
XML 문서 (1, 16)에 오류가 있습니다.
아무도 비어 있지 않은 속성 값을 정수로 역 결합 화하는 동시에 빈 값을 가진 속성을 nullable 형식 (null)으로 역 배열 화하는 방법을 조언 할 수 있습니까? 이에 대한 트릭이 있으므로 각 필드를 수동으로 역 생성 화 할 필요가 없습니까 (실제로 많은 필드가 있음)?
ahsteele의 의견 후 업데이트 :
-
내가 아는 한이 속성은 XmlElementAttribute에서만 작동합니다.이 속성은 어떤 요소 든 본문 텍스트 요소에 콘텐츠가 없음을 지정합니다. 하지만 XmlAttributeAttribute에 대한 솔루션을 찾아야합니다. 어쨌든 나는 그것을 제어 할 수 없기 때문에 xml을 사용할 수 없습니다.
-
이 속성은 속성 값이 비어 있지 않을 속성이없는 경우에만 작동합니다. attr에 빈 값 (attr = '')이 있으면 XmlSerializer 생성자가 예상대로 실패합니다.
public class Element { [XmlAttribute("attr")] public int Value { get; set; } [XmlIgnore] public bool ValueSpecified; }
Alex Scordellis 의이 블로그 게시물과 같은 사용자 지정 Nullable
이 블로그 게시물의 수업을 내 문제에했습니다.
[XmlAttribute("attr")] public NullableInt Value { get; set; }
그러나 XmlSerializer가 생성자는 InvalidOperationException과 함께 실패합니다.
TestConsoleApplication.NullableInt 형식의 'Value'멤버를 직렬화 할 수 없습니다.
XmlAttribute / XmlText는 IXmlSerializable을 구현하는 형식을 인코딩하는 데 사용할 수 없습니다.}
추악한 대리 솔루션 (여기 에이 코드를하는 것이 부끄럽습니다. :)) :
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; } }
그러나 나는 소비자를 위해 내 클래스의 인터페이스를 깨뜨리기 때문에 이와 같은 솔루션을 찾고 싶지 않습니다. IXmlSerializable 인터페이스를 수동으로 구현하는 것이 좋습니다.
현재 전체 Element 클래스에 대해 IXmlSerializable을 구현해야 할 것입니다 (크다). 간단한 해결 방법이 없습니다.
작동합니다.
[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?); }
}
IXmlSerializable 인터페이스를 구현하여 문제를 해결했습니다. 더 쉬운 방법을 찾을 수 없습니다.
다음은 테스트 코드 샘플입니다.
[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 데이터를 처리 할 때 다음 기사와 게시물이 도움이되는 것을 발견했습니다.
C #에서 XmlSerializer를 사용하여 값 형식을 nullable로 만드는 방법에 대한 답변 -직렬화 는 XmlSerializer의 멋진 트릭을 자세히 설명합니다. 특히 XmlSerialier는 XXXSpecified 부울 속성을 검색하여 null을 무시할 수있는 포함 여부를 결정합니다.
Alex Scordellis 는 좋은 답변 을 받았습니다. StackOverflow 질문을 받았습니다 . Alex는 또한 자신의 블로그에서 XmlSerializer를 사용하여 Nullable <int>로 역으로 만들었던 문제에 대해 좋은 글을 올렸습니다 .
Xsi : nil 속성 바인딩 지원 에 대한 MSDN 문서 도 유용합니다. IXmlSerializable Interface 에 대한 문서와 마찬가지로 자신의 구현을 작성하는 것이 최후의 수단이어야합니다.
내 대답을 모자에 던질 수 있다고 생각했습니다. IXmlSerializable 인터페이스를 구현하는 사용자 지정 형식을 만들어이 문제를 해결했습니다.
다음 노드가있는 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 구조체
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));
}
}
}
'ProgramingTip' 카테고리의 다른 글
Spring 5.0.3 RequestRejectedException : URL이 갑자기 발생하지 않아 요청이 거부되었습니다. (0) | 2020.10.30 |
---|---|
ASPXAUTH 쿠키 란 무엇입니까? (0) | 2020.10.30 |
표준 HTML5 유효성 검사 (양식)를 트리거 하시겠습니까? (0) | 2020.10.30 |
포함 할 PHP 전달 변수 (0) | 2020.10.30 |
명령 줄에서 CMake 옵션 ()을 설정하는 방법 (0) | 2020.10.30 |