在嵌套属性上使用XmlAttributeOverrides [英] Using XmlAttributeOverrides on Nested Properties

查看:168
本文介绍了在嵌套属性上使用XmlAttributeOverrides的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用XmlAttributeOverrides来控制在类被序列化之后在xml中出现的类属性。它适用于根类但不在嵌套属性上的属性。下面是一个简单的例子来说明我要完成的工作。

I am trying to use XmlAttributeOverrides to control which class properties appear in the xml after the class has been serialized. It works on properties that are on the "root" class but not on nested properties. Here is a simple example to illustrate what I'm trying to accomplish.

我的类层次结构如下:

public class Main
{
    public string Name { get; set; }
    public Location Address { get; set; }
}

public class Location
{
    public string StreetAddress { get; set; }
    public Contact ContactInfo{ get; set; }
}

public class Contact
{
    public string PhoneNumber { get; set; }
    public string EmailAddr { get; set; }
}



When I serialize Main(), I get something like this:

<Main>
    <Name></Name>
    <Address>
        <StreetAddress></StreetAddress>
        <ContactInfo>
            <PhoneNumber></PhoneNumber>
            <EmailAddr></EmailAddr>
        </ContactInfo>
    </Address>
</Main>

我可以使用以下方法防止名称或地址出现:

What I am able to do is keep either Name or Address from appearing by using this:

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
attribs.XmlIgnore = true;
attribs.XmlElements.Add(new XmlElementAttribute("Address"));
overrides.Add(typeof(Main), "Address", attribs);
xs = new XmlSerializer(typeof(Main), overrides);

我还需要做的是保持Main.Address.ContactInfo序列化 SOMETIMES (如果为空)。我尝试以下但是他们不工作:

What I need to also be able to do is keep Main.Address.ContactInfo from being serialized SOMETIMES (if it's empty). I tried the following but they didn't work:

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
attribs.XmlIgnore = true;
attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo "));
overrides.Add(typeof(Contact), "ContactInfo ", attribs);
xs = new XmlSerializer(typeof(Contact), overrides);

和...

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
attribs.XmlIgnore = true;
attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo "));
overrides.Add(typeof(Main.Address.ContactInfo), "ContactInfo ", attribs);
xs = new XmlSerializer(typeof(Main.Address.ContactInfo), overrides);

我实际上尝试了更多,包括使用XPath语句指定属性名称为目标,不希望用失败的尝试填充此页面。

I've actually tried a lot more, including using XPath statements to designate the attribute name to target but didn't want to fill this page up with failed attempts. Is what I'm asking even possible by this method?

推荐答案

有更简单的方法来实现你想要的。

There are easier ways to achieve what you're looking for.

你说你想要实现的是不要序列化 / Main / Address / ContactInfo if ContactInfo 不包含数据。

You said that what you are trying to achieve is to not serialize /Main/Address/ContactInfo if ContactInfo contains no data.

如果你保留代码,它将序列化Main的所有属性, null或空或不。第一步,你需要为所有对象添加一个 XmlSerializerNamespaces 属性,否则每个空对象将被序列化为< myElement xsi:nil =true/> 。这可以很容易地实现,如下所示:

If you leave your code as is, it will serialize all of Main's properties, whether they are null or empty or not. The first step, is you need to add a XmlSerializerNamespaces property to all of your objects or each empty object will be serialized as <myElement xsi:nil="true" />. This can be accomplished easily, as follows:

public MyXmlElement
{
    public MyXmlElement()
    {
        // Add your own default namespace to your type to prevet xsi:* and xsd:*
        // attributes from being generated.
        this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
            new XmlQualifiedName(string.Empty, "urn:myDefaultNamespace") });
    }

    [XmlElement("MyNullableProperty", IsNullable=false)]
    public string MyNullableProperty
    {
        get
        {
            return string.IsNullOrWhiteSpace(this._myNullableProperty) ? 
                null : this._myNullableProperty;
        }
        set { this._myNullableProperty = value; }
    }

    [XmlNamespacesDeclaration]
    public XmlSerializerNamespaces Namespaces { get { return this._namespaces; } }
    private XmlSerializerNamespaces _namespaces;
}

上面的代码声明了一个 Namespaces 属性,它包含XML对象的所有相关命名空间。您应该为所有对象提供一个默认命名空间(在上面的代码之后建模)。这可以防止在对象序列化时为其输出 xsi:* xsd:* 属性。此外,使用 System.Xml.Serialization.XmlElementAttribute 指定元素不可为空。

The code above declares a Namespaces property that holds all the relevant namespaces for the XML object. You should provide a default namespace for all of your objects (modeled after the code above). This prevents the xsi:* and xsd:* attributes from being output for your objects when they are serialized. Also, specify that the element is not nullable by using the System.Xml.Serialization.XmlElementAttribute.

通过检查 string.IsNullOrWhiteSpace(someVariable)并返回null,当上述操作完成后,
属性将不会被序列化。

Furthermore, by checking for string.IsNullOrWhiteSpace(someVariable) and returning null, then the property will not be serialized when the above has been done.

所以,把这些放在一起为你的位置类:

So, putting this all together for your Location class:

public class Location
{
    // You should have a public default constructor on all types for (de)sereialization.
    public Location()
    {
        this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
            new XmlQualifiedName(string.Empty, "urn:myNamespace"); // Default namespace -- prevents xsi:nil="true" from being generated, as well as xsd:* attributes.
        });
    }

    public string StreetAddress
    {
        // If you don't want <StreetAddress xsi:nil="true" /> to be generated, do this:
        get { return string.IsNullOrEmpty(this._streetAddress) ? null : this._streetAddress; }

        // Otherwise, if you don't care, just do
        // get;

        // Only need to implement setter if you don't want xsi:nil="true" to be generated.
        set { this._streetAddress = value; }

        // Otherwise, just
        // set;
    }
    private string _streetAddress;

    [XmlElement("ContactInfo", IsNullable=false)]
    public Contact ContactInfo
    {
        // You must definitely do this to prevent the output of ContactInfo element
        // when it's null (i.e. contains no data)
        get
        {
            if (this._contactInfo != null && string.IsNullOrWhiteSpace(this._contactInfo.PhoneNumber) && string.IsNullOrWhiteSpace(this._contactInfo.EmailAddr))
                return null;

             return this._contactInfo;
        }

        set { this._contactInfo = value; }
    }
    private Contact _contactInfo;

    [XmlNamespacesDeclarations]
    public XmlSerializerNamespaces Namespaces
    {
        get { return this._namespaces; }
    }
    private XmlSerializerNamespaces _namespaces;
}

位置类时,如果没有属性为空,空或空格,或者属性不应该被序列化为XML,则空的 ContactInfo ContactInfo 本身为空。

With these changes to your Location class, the empty ContactInfo property should no longer be serialized to XML when none of the properties are null, empty, or whitespace, or if ContactInfo itself is null.

您应该对其他对象进行类似的更改。

You should make similar changes to your other objects.

查看我的其他stackoverflow答案更多的.NET XML序列化:

See my other stackoverflow answers for more on .NET XML serialization:

  • XmlSerializer: remove unnecessary xsi and xsd namespaces
  • Omitting all xsi and xsd namespaces when serializing an object in .NET?
  • Suppress xsi:nil but still show Empty Element when Serializing in .Net

这篇关于在嵌套属性上使用XmlAttributeOverrides的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆