Ответ 1
XmlSerializer
не поддерживает прямую привязку к элементам, которые одновременно имеют xsi:nil="true"
вместе с другими значениями атрибутов; см. Xsi: nil Поддержка привязки атрибутов: атрибут nil и другие атрибуты.
Таким образом, вам нужно исправить атрибут вручную.
Если вы хотите создать элемент без содержимого и двух атрибутов, один из которых называется NV
, а другой всегда xsi:nil="true"
, вы можете изменить свой класс testTag01
, чтобы иметь свойство NV
как а также синтетическое свойство, имеющее правильное пространство имен и имя:
public class testTag01
{
[XmlAttribute]
public string NV { get; set; }
[XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Nil { get { return "true"; } set { } }
}
Если вы иногда хотите иметь xsi:nil="true"
, но в других случаях хотите, чтобы элемент имел контент, соответствующий вашему SomeEnum
, вам нужно сделать что-то более сложное, так как xsi:nil="true"
должен быть подавлен, когда элемент имеет содержание:
public class testTag01
{
[XmlAttribute]
public string NV { get; set; }
[XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Nil { get { return SomeEnum == null ? "true" : null; } set { } }
public bool ShouldSerializeNil() { return SomeEnum == null; }
[XmlIgnore]
public SomeEnum? SomeEnum { get; set; }
[XmlText]
public string SomeEnumText
{
get
{
if (SomeEnum == null)
return null;
return SomeEnum.Value.ToString();
}
set
{
// See here if one needs to parse XmlEnumAttribute attributes
// http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value
value = value.Trim();
if (string.IsNullOrEmpty(value))
SomeEnum = null;
else
{
try
{
SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, false);
}
catch (Exception)
{
SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, true);
}
}
}
}
}
(Элемент, который одновременно имеет и xsi:nil="true"
и контент, будет нарушением стандарта XML, надеюсь, у вас нет этого.)
Затем используйте его как:
public class TestClass
{
[XmlElement("testTag.01")]
public testTag01 TestTag { get; set; }
public static void Test()
{
Test(new TestClass { TestTag = new testTag01 { NV = "123123" } });
Test(new TestClass { TestTag = new testTag01 { NV = "123123", SomeEnum = SomeEnum.SomeValue } });
}
private static void Test(TestClass test)
{
var xml = test.GetXml();
var test2 = xml.LoadFromXML<TestClass>();
Console.WriteLine(test2.GetXml());
Debug.WriteLine(test2.GetXml());
if (test2.TestTag.NV != test.TestTag.NV)
{
throw new InvalidOperationException("test2.TestTag.NV != test.TestTag.NV");
}
}
}
Выход XML выглядит следующим образом:
<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <testTag.01 NV="123123" xsi:nil="true" /> </TestClass>
или
<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <testTag.01 NV="123123">SomeValue</testTag.01> </TestClass>
Прототип fiddle с использованием этих методов расширения:
public static class XmlSerializationHelper
{
public static T LoadFromXML<T>(this string xmlString, XmlSerializer serializer = null)
{
T returnValue = default(T);
using (StringReader reader = new StringReader(xmlString))
{
object result = (serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
if (result is T)
{
returnValue = (T)result;
}
}
return returnValue;
}
public static string GetXml<T>(this T obj, XmlSerializerNamespaces ns = null, XmlWriterSettings settings = null, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
settings = settings ?? new XmlWriterSettings() { Indent = true, IndentChars = " " }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(typeof(T))).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
}
}
}