在嵌套的属性使用XmlAttributeOverrides(Using XmlAttributeOv

2019-09-02 22:23发布

我试图用XmlAttributeOverrides来控制类属性出现在XML类已系列化之后。 它适用于那些对“根”级,但不是嵌套属性的属性。 下面是一个简单的例子来说明什么,我试图完成。

我的类层次结构如下:

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; }
}

当我序列的Main(),我得到的是这样的:

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

我所能做的就是保持名称或地址通过使用该出现的:

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序列化(如果它是空的)。 我尝试以下,但他们没有工作:

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语句来指定属性名的目标,但不希望填补这一页了失败的尝试。 就是我用这种方法要求甚至可能吗?

Answer 1:

还有更简单的方法来实现你在找什么。

你说,你正在努力实现的是不序列/Main/Address/ContactInfo如果ContactInfo不包含任何数据。

如果你离开你的代码,它会序列化所有主要的属性,无论是空或空。 第一步,是你需要一个补充XmlSerializerNamespaces属性,你所有的物体或每个空的对象将被序列化为<myElement xsi:nil="true" /> 这可以很容易实现,具体如下:

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

此外,通过检查string.IsNullOrWhiteSpace(someVariable)并返回null,则该属性不会被当上述已经完成系列化。

因此,把所有这些组合起来为你的Location类:

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;
}

这些变化对你的Location类,空ContactInfo属性应该不再被序列化到XML时,任何属性都为空,空,或空格,或者如果ContactInfo本身是空的。

你应该让你的其他对象类似的变化。

见我的其他计算器的答案以获得更多关于.NET XML序列化:

  • XmlSerializer的:删除不必要的XSI和XSD命名空间
  • 序列化的.NET对象时,省略所有XSI和XSD命名空间?
  • 抑制XSI:无,但在.net序列化时仍显示空元素


Answer 2:

对于任何人试图用XmlAttributeOverrides要做到这一点,事实证明,@ user1437872非常接近找到答案。 这里是重写代码以忽略嵌套元素的ContactInfo。

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


Answer 3:

有没有必要到的ContactInfo元素添加到attribs

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


文章来源: Using XmlAttributeOverrides on Nested Properties