C#使用XmlText序列化XmlElement

时间:2017-12-04 20:39:23

标签: c# xml xmlserializer

我需要复制这种XML格式:

<item>
    <attribute1>1</attribute1>
    <attribute2 something="true">
        2
    </attribute2>
    <attribute3 something="false">
        3
    </attribute3>
    <!-- goes on until attribute25 -->
</item>

我目前正在使用这样的东西来实现我的目标:

Item.cs:

[XmlType(TypeName = "item")]
public class Item {

    [XmlElement("attribute1")]
    public CustomElement<string> Attribute1 { get; set; }

    [XmlElement("attribute2")]
    public CustomElement<string> Attribute2 { get; set; }

    [XmlElement("attribute3")]
    public CustomElement<string> Attribute3 { get; set; }

    // Etc Etc
}

CustomElement.cs:

/// <summary>
///     Represents a CustomElement.
/// </summary>
/// <typeparam name="T">The type for the value of the element.</typeparam>

public class CustomElement<T>
{
    [XmlIgnore] public T Value;

    [XmlText]
    public T XmlValue => Value;

    public CustomElement()
    {
    }

    public CustomElement(T value)
    {
        Value = value;
    }

    [XmlIgnore]
    public bool? Something { get; set; }

    [XmlAttribute("something")]
    public bool XmlSomething
    {
        get => Something != null && Something.Value;
        set => Something = value;
    }

    public bool XmlSomethingSpecified => Something.HasValue;

    public static implicit operator CustomElement<T>(T x)
    {
        return new CustomElement<T>(x);
    }
}

然而,在序列化我的Item后,我得到了:

<item>
    <attribute1 />
    <attribute2 />
    <attribute3 />
</item>

如何修复我的CustomElement课程以使价值不会丢失?

1 个答案:

答案 0 :(得分:3)

这里有几个问题:

  1. 您正在尝试序列化XmlValue成员作为为CustomElement<T>实例生成的元素的元素值,但您已将其定义为只读< / strong> expression-bodied member

    public T XmlValue => Value;
    

    XmlSerializer只会序列化公共读/写属性和字段,因此您必须添加setter和getter:

    [XmlText]
    public T XmlValue { get => Value; set => Value = value; }
    

    或者,为了简化您的模型,您可以完全删除XmlValue并直接序列化Value,并使用[XmlText]进行标记。 XML序列化属性可以应用于字段和属性。

  2. 您正尝试使用{propertyName}Specified pattern在基础值为<something>时禁止null元素的序列化。此模式主要用于跟踪,无论是否遇到关联元素,因此xxxSpecified属性必须标有[XmlIgnore]

    [XmlIgnore]
    public bool XmlSomethingSpecified => Something.HasValue;
    

    或者,由于您实际上并不需要跟踪<something>元素的存在,因此您可以通过切换到ShouldSerialize{PropertyName}()模式来简化模型:

    public bool ShouldSerializeXmlSomething() => Something.HasValue;
    

    ShouldSerialize() vs Specified Conditional Serialization Pattern

  3. 中描述了两种模式之间的差异
  4. 如果您的Item类型将成为XML文档的根元素,则必须使用[XmlRoot("item")]对其进行标记,以使根元素的名称为{{1 }}:

    <item>
  5. 在您的c#代码中,您已将[XmlRoot("item")] [XmlType(TypeName = "ci")] public class Item { // Etc Etc } 属性标记为XmlSomething,但在您的XML [XmlElement]中显示为元素:{{ 1}}。

    如果您确实希望它成为元素,则必须使用something标记<something>true</something>

    XmlSomething
  6. 在您的问题中,您展示了一个带有非布尔文本值的[XmlElement]元素的示例:

    [XmlElement("something")]
    public bool XmlSomething
    {
        get => Something != null && Something.Value;
        set => Something = value;
    }
    

    我认为这是问题中的拼写错误,但如果没有,则需要重新设计<something>类型,以使<attribute3> 3 <something>text</something> </attribute3> 成为CustomElement<T>

  7. 示例工作Roslyn .Net fiddlesecond包含Something的建议简化,third string显示为子元素。

    第二小提琴的类看起来像:

    CustomElement<T>