2

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 が時々シリアル化されないようにすることです(空の場合)。次のことを試しましたが、うまくいきませんでした。

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 ステートメントを使用して対象の属性名を指定するなど、実際にはもっと多くのことを試しましたが、失敗した試みでこのページを埋めたくありませんでした。私が求めていることは、この方法でも可能ですか?

4

3 に答える 3

4

あなたが探しているものを達成するためのより簡単な方法があります。

あなたが達成しようとしているのは、データが含まれていない/Main/Address/ContactInfo場合はシリアル化しないことだと言いましたContactInfo

コードをそのままにしておくと、Main のプロパティが null か空かどうかにかかわらず、すべてシリアル化されます。最初のステップは、すべてのオブジェクトにプロパティを追加する必要がある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:*また、 を使用して、要素が null 可能でないことを指定しますSystem.Xml.Serialization.XmlElementAttribute

さらに、null をチェックしstring.IsNullOrWhiteSpace(someVariable)て返すことにより、上記が行われたときにプロパティがシリアル化されなくなります。

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クラスへのこれらの変更により、どのプロパティも null、空、または空白でない場合、またはそれ自体が nullContactInfoの場合、空のプロパティは XML にシリアル化されなくなります。ContactInfo

他のオブジェクトにも同様の変更を加える必要があります。

.NET XML シリアル化の詳細については、他のスタック オーバーフローの回答を参照してください。

于 2013-05-13T16:50:59.657 に答える