I have this XML format I need to replicate:
<item>
<attribute1>1</attribute1>
<attribute2 something="true">
2
</attribute2>
<attribute3 something="false">
3
</attribute3>
<!-- goes on until attribute25 -->
</item>
I'm currently using something like this to achieve what I want:
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);
}
}
However, after serializing my Item
I get:
<item>
<attribute1 />
<attribute2 />
<attribute3 />
</item>
How do I fix my CustomElement
class so the value doesn't get lost?
You have several problems here:
You are trying to serialize the XmlValue
member as the element value for the element generated for an instance of CustomElement<T>
, but you have defined it as a read-only expression-bodied member :
public T XmlValue => Value;
XmlSerializer
will only serialize public read/write properties and fields, so you must add a setter as well as a getter:
[XmlText] public T XmlValue { get => Value; set => Value = value; }
Alternatively, to simplify your model you could eliminate XmlValue
entirely and serialize Value
directly by marking it with [XmlText]
. XML serialization attributes can be applied to fields as well as properties.
You are trying to suppress serialization of the <something>
element when the underlying value is null
using the {propertyName}Specified
pattern . This pattern is primarily used for tracking whether or not an associated element is encountered, and so the xxxSpecified
property must be marked with [XmlIgnore]
:
[XmlIgnore] public bool XmlSomethingSpecified => Something.HasValue;
Or, since you don't actually need to track the presence of the <something>
element, you could simplify your model by switching to the ShouldSerialize{PropertyName}()
pattern:
public bool ShouldSerializeXmlSomething() => Something.HasValue;
The differences between the two patterns are described in ShouldSerialize () vs Specified Conditional Serialization Pattern .
If your Item
type is going to be the root element of your XML document, you must mark it with [XmlRoot("item")]
to make the root element's name be <item>
:
[XmlRoot("item")] [XmlType(TypeName = "ci")] public class Item { // Etc Etc }
In your c# code you have marked the XmlSomething
property with [XmlElement]
but in your XML something
is shown as an element : <something>true</something>
.
If you really want it to be an element you must mark XmlSomething
with [XmlElement]
:
[XmlElement("something")] public bool XmlSomething { get => Something != null && Something.Value; set => Something = value; }
In your question, you show an example of a <something>
element with a non-boolean textual value:
<attribute3> 3 <something>text</something> </attribute3>
I reckon this is a typo in the question, but if not, you will need to redesign your CustomElement<T>
type to make Something
be a string
.
Sample working Roslyn .Net fiddle , and a second with the suggested simplifications for CustomElement<T>
, and a third where <something>
appears as a child element.
The classes from the second fiddle look like:
public class CustomElement<T>
{
[XmlText]
public T 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 ShouldSerializeXmlSomething() => Something.HasValue;
public static implicit operator CustomElement<T>(T x)
{
return new CustomElement<T>(x);
}
}
[XmlRoot("item")]
[XmlType(TypeName = "ci")]
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
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.