簡體   English   中英

序列化為XML時重命名類

[英]Rename class when serializing to XML

我正在嘗試序列化如下所示的Outer類,並從序列化的XML創建一個XElement 它具有Inner類型的屬性。 我想將Inner (更改為Inner_X )和Outer (更改為Outer_X )的名稱。

class Program
{
    static void Main(string[] args)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (TextWriter streamWriter = new StreamWriter(memoryStream))
            {
                var xmlSerializer = new XmlSerializer(typeof(Outer));

                xmlSerializer.Serialize(streamWriter,  new Outer());

                XElement result = XElement.Parse(Encoding.ASCII.GetString(memoryStream.ToArray()));
            }
        }
    }
}

[XmlType("Outer_X")]
public class Outer
{
    public Outer()
    {
        this.InnerItem = new Inner();
    }

    public Inner InnerItem { get; set; }
}

[XmlType("Inner_X")]
public class Inner
{
}

這將創建一個如下所示的XElement

<Outer_X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <InnerItem />
</Outer_X>

我想要的是:

<Outer_X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Inner_X />
</Outer_X>

我想保留有關如何使用該類重命名該類的信息。 我以為可以用XmlType屬性來做到這一點。 但是,將忽略此屬性,而是使用屬性名稱。

我看過這里這里 ,以及其他地方,覺得這應該可行。 我想念什么?

澄清度

通過“保留有關如何使用該類重命名該類的信息” ,我的意思是,術語Inner_X僅應出現在Inner類中。 它根本不應出現在“ Outer類中。

您需要設置屬性的元素名稱,而不是內部類的xml類型。 嘗試這個:

[XmlType("Outer_X")]
public class Outer
{
    public Outer()
    {
        this.InnerItem = new Inner();
    }

    [XmlElement("Inner_X")]
    public Inner InnerItem { get; set; }
}


public class Inner
{
}

XmlSerializer序列化一個類型時,該類型本身將控制為其屬性創建的元素的名稱。 即,屬性名稱將成為元素名稱,除非被XmlElementAttribute.ElementName靜態覆蓋。 XmlTypeAttribute.TypeName通常僅在以下情況下才控制元素名稱:當將其應用的類型的實例序列化為某些包含類型的屬性時,例如,當它是根元素或包含在使用外部容器元素序列化的collection。 在給定類型中存在相同類型的多個屬性的情況下,這種設計可以避免名稱沖突。

但是,多態屬性類型存在例外。 對於這些, XmlSerializer可以選擇使用每種可能的多態類型的XML類型名稱作為元素名稱,從而標識從中創建元素的實際c#類型。 要啟用此功能,必須[XmlElement(typeof(TDerived))]屬性添加多個[XmlElement(typeof(TDerived))]屬性,每種可能的類型TDerived

您可以通過引入偽多態代理屬性來使用此功能來生成所需的XML:

[XmlType("Outer_X")]
public class Outer
{
    public Outer()
    {
        this.InnerItem = new Inner();
    }

    [XmlIgnore]
    public Inner InnerItem { get; set; }

    [XmlElement(typeof(Inner))]
    [XmlElement(typeof(object))]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public object InnerItemXmlProxy
    {
        get
        {
            return InnerItem;
        }
        set
        {
            InnerItem = (Inner)value;
        }
    }
}

然后輸出就如您所願:

<Outer_X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Inner_X />
</Outer_X>

原型擺弄

但是,正如@evk所說,如果您的Outer類包含多個相同類型的屬性,則無法完成此操作。

您需要考慮的另一種選擇:如果您只是不想在多個位置手動復制"Inner_X"類型名稱字符串(即[XmlType(string name)][XmlElement(string name)]屬性),可以通過將類型名稱設為public const來集中它們:

[XmlType(Outer.XmlTypeName)]
public class Outer
{
    public const string XmlTypeName = "Outer_X";

    public Outer()
    {
        this.InnerItem = new Inner();
    }

    [XmlElement(Inner.XmlTypeName)]
    public Inner InnerItem { get; set; }
}

[XmlType(Inner.XmlTypeName)]
public class Inner
{
    public const string XmlTypeName = "Inner_X";
}

更新資料

我剛剛注意到您的評論, 我打算將Inner用作抽象基類,該基類的每個子類將序列化為不同的元素名稱 如果是這種情況,則可以確實使XmlSerializer使用XML類型名稱作為元素名稱-但僅當它可以靜態確定屬性類型實際上是多態的(由於存在多個 [XmlElement(typeof(TDerived))]屬性。 因此,以下類將生成您需要的XML:

[XmlType("Outer_X")]
public class Outer
{
    public Outer()
    {
        this.InnerItem = new InnerX();
    }

    [XmlElement(typeof(InnerX))]
    [XmlElement(typeof(Inner))] // Necessary to inform the serializer of polymorphism even though Inner is abstract.
    public Inner InnerItem { get; set; }
}

public abstract class Inner
{
}

[XmlType("Inner_X")]
public class InnerX : Inner
{
}

這是非常容易實現的。 您需要使用XmlRootAttributeclassXmlElementAttribute的成員解釋這里在MSDN上

[XmlRoot(ElementName = "Outer_X")]
public class Outer
{    
    [XmlElement(ElementName = "Inner_X")]
    public Inner InnerItem { get; set; } = new Inner();
}

public class Inner { }

我創建了一個工作的.NET Fiddle來舉例說明。 這樣的問題解答似乎解決了類似的問題。 最后,在將XML解碼為字符串時,您可能應該使用其他編碼,對嗎? 根據 ,字符串是UTF-16編碼-不是什么大問題,但想我會呼吁關注它。

我共享的小提琴使用以下XML:

<Outer_X xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Inner_X />
</Outer_X>

更新資料

在澄清您的問題后,現在我明白了您的要求。 不幸的是,(據我所知)無法通過屬性來控制它。 您必須創建自己的XML序列化器/反序列化器,或者接受屬性支持存在限制的事實。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM