在嵌套属性上使用XmlAttributeOverrides

本文关键字:XmlAttributeOverrides 嵌套 属性 | 更新日期: 2023-09-27 18:13:16

我试图使用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>

我所能做的就是通过使用这个来保持Name或Address不出现:

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被序列化有时(如果它是空的)。我尝试了以下方法,但都不起作用:

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语句将属性名称指定为target,但不想让失败的尝试填满这个页面。我问的问题能用这种方法实现吗?

在嵌套属性上使用XmlAttributeOverrides

对于任何试图使用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);

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

您说如果ContactInfo不包含数据,您想要实现的是不序列化/Main/Address/ContactInfo

如果你让你的代码保持原样,它将序列化Main的所有属性,不管它们是空还是空。第一步,你需要添加一个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本身为空,则空ContactInfo属性将不再被序列化为XML。

你应该对你的其他对象做类似的修改。

关于。net XML序列化的更多信息,请参阅我的其他stackoverflow答案:
    XmlSerializer:删除不必要的xsi和xsd命名空间
  • 在。net中序列化对象时省略所有xsi和xsd名称空间?
  • 禁止xsi:nil,但在。net中序列化时仍显示空元素

不需要为属性添加ContactInfo元素

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
attribs.XmlIgnore = true;
overrides.Add(typeof(Address), "ContactInfo ", attribs);
xs = new XmlSerializer(typeof(Main), overrides);
相关文章:
  • 没有找到相关文章