【问题标题】:Can [XmlText] serialization be nullable?[XmlText] 序列化可以为空吗?
【发布时间】:2012-09-05 14:25:05
【问题描述】:

我有一个包含我希望用 XmlSerializer 序列化的数组的类:

[XmlArray("properties")]
[XmlArrayItem("property", IsNullable = true)]
public List<Property> Properties { get; set; }

Property是一个包含一个属性和一些XmlText的类:

[XmlAttribute("name")]
public string Name { get; set; }

[XmlText]
public string Value { get; set; }

问题是当Value为null时,序列化为空字符串:

<property name="foo" />

而不是 null。我正在寻找要完全省略的值,或者看起来像这样:

<property name="foo" xsi:nil="true" />

是否可以根据XmlText 值将列表中的元素清空?我真的想避免自定义序列化,但在这种情况下,也许其他一些序列化框架会更好?

【问题讨论】:

  • 只是从臀部射击 - 尝试使用 public string? Value 而不是仅仅使用 public string Value 并让我们知道它是否有所作为。
  • string 是引用类型,所以怕是isn't nullable in that way
  • 啊,我明白了。 this 有什么帮助吗?

标签: .net xmlserializer


【解决方案1】:

XmlArrayItemAttribute 类中使用IsNullable=true。举个例子。

[XmlRoot("Root")]
public class Root
{
    [XmlArrayItem("Element", IsNullable = true)]
    public string[] Elements { get; set; }
}

Visual Studion 2012 和 .Net 4.5 中的一些示例代码:

using System.Xml.Serialization;

...

// Test object
Root root;
root = new Root();
root.Elements = new string[] { null, "abc" };

using(MemoryStream stream = new MemoryStream())
{
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(Root));
    xmlSerializer.Serialize(stream, root);

    Console.WriteLine(new string(Encoding.UTF8.GetChars(stream.GetBuffer())));
}

输出是(为清楚起见添加了换行符):

<?xml version="1.0"?>
<Root 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Element>
    <string xsi:nil="true" />
    <string>abc</string>
  </Element>
</Root>

并且具有复杂类型(也在 Visual Studio 2012 上的 .Net 4.5 中):

    public class MyProperty
    {
        public string Foo { get; set; }
    }

    [XmlRoot("Root")]
    public class Root
    {
        [XmlArrayItem("Element", IsNullable = true)]
        public MyProperty[] Elements { get; set; }
    }

    ,,,

    Root root;
    root = new Root();
    root.Elements = new MyProperty[] { null, new MyProperty{ Foo = "bar" } };

    // Other code is as above

使用上面相同的代码产生:

<?xml version="1.0"?>
<Root 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Elements>
    <Element xsi:nil="true" />
    <Element>
      <Foo>bar</Foo>
    </Element>
  </Elements>
</Root>

还要记住,类型必须是引用类型(例如,不是结构)才能写出xsi:nil=true

【讨论】:

  • 我根本没有使用XmlElement。我有一个架构,但恐怕我不明白这会有什么帮助..?
  • 我的IsNullable = true 声明中有[XmlArrayItem]。当数组项是复杂类型时,它的工作方式似乎有所不同。
  • @ladenedge 我尝试使用复杂类型(请参阅更新的答案),它仍然以xsi:nil="true" 输出。可能这是框架早期版本中的错误,或者复杂类型是结构或其他值类型。
  • 对不起,我不是很清楚。这个问题是关于当元素的[XmlText] 为空时将元素设置为nil,而不是当数组项本身为空时。
  • @ladenedge 当 Value 为 null 时,您希望将 Value 作为 nil 序列化为 XML,或者从序列化中完全省略 Property?如果是前者,如果 Value 被序列化为 XML 元素,您可以这样做,如我的回答中所述,但如果它是 XML 属性则不能。如果是后者,您可以使用带有 OnSerializatoinAttribute 的方法预先从 List 中临时删除 Property 对象,然后将其添加回使用 OnDeserializationAttribute 的方法中。
【解决方案2】:

一个想法 - 您可以使用“NameSpecified”,但在 get 中检查“Value”的值。意思是,如果Value为null,那么Name也不会输出。

不幸的是,您仍然有一个空属性 xml 元素,但是;我希望这更容易接受......

class Program
{
    static void Main(string[] args)
    {
        ObjectWithProperties obj = new ObjectWithProperties()
        {
            Properties = new List<Property>()
        };

        Property p = new Property();
        p.Name = "This WILL Show Up";
        p.Value = "I'm here";
        obj.Properties.Add(p);

        Property p1 = new Property();
        p1.Name = "This Will NOT Show Up";
        obj.Properties.Add(p1);

        Console.WriteLine(ToXmlString(obj));
        Console.ReadLine();
    }

    public static string ToXmlString(object value)
    {
        if (value == null) return string.Empty;
        XmlSerializer ser = new XmlSerializer(value.GetType());
        MemoryStream ms = new MemoryStream();
        ser.Serialize(ms, value);
        return Encoding.UTF8.GetString(ms.ToArray());
    }

}
public class ObjectWithProperties
{
    [XmlArray("properties")]
    [XmlArrayItem("property", IsNullable = true)]
    public List<Property> Properties { get; set; }
}

public class Property
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlIgnore]
    public bool NameSpecified
    {
        get { return !string.IsNullOrEmpty(Value); }
    }

    [XmlText]
    public string Value { get; set; }

}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 2010-09-23
  • 1970-01-01
相关资源
最近更新 更多