Reputation: 41
I am having an issue with serializing and object, I can get it to create all the correct outputs except for where i have an Element that needs a value and an attribute. Here is the required output:
<Root>
<Method>Retrieve</Method>
<Options>
<Filter>
<Times>
<TimeFrom>2009-06-17</TimeFrom>
</Times>
<Document type="word">document name</Document>
</Filter>
</Options>
</AdCourierAPI>
I can build all of it but can not find a way to set the Document type attribute, here is a segment of the object class
[XmlRoot("Root"), Serializable]
public class Root
{
[XmlElement("Method")]
public string method="RetrieveApplications";
[XmlElement("Options")]
public _Options Options;
}
public class _Options
{
[XmlElement("Filter")]
public _Filter Filter;
}
public class _Filter
{
[XmlElement("Times")]
public _Times Times;
[XmlElement("Documents")]
public string Documents;
}
which gives me:
<Document>document name</Document>
rather than:
<Document type="word">document name</Document>
but I can not find a way to correct this, please advise.
Thanks
Upvotes: 41
Views: 74547
Reputation: 467
You can use XmlWriter instead XmlSerialization to get this effect. It is more complex but if you have a lot of strings in model it will be cleaner solution.
Create your own CustomeAttribute, for example:
[System.AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class MyCustomAttribute : System.Attribute
{
public MyCustomAttribute (string type)
{
MyType = type;
}
public string MyType { get; set; }
}
Then in model add it, like that:
public class MyModel
{
[MyCustom("word")]
public string Document { get; set; }
[MyCustom("time")]
public string Time { get; set; }
}
The last part is to create xml with this arguments. You can do it likes that:
var doc = new XmlDocument();
MyModel myModel = new MyModel();//or get it from somewhere else
using (Stream s = new MemoryStream())
{
var settings = new XmlWriterSettings();
settings.Async = true;
settings.Indent = true;
var writer = XmlTextWriter.Create(s, settings);
await writer.WriteStartDocumentAsync();
await writer.WriteStartElementAsync(null,"Root", null);
myModel.GetType().GetProperties().ToList().ForEach(async p =>
{
dynamic value = p.GetValue(myModel);
writer.WriteStartElement(p.Name);
var myCustomAttribute = p.GetCustomAttributes(typeof(MyCustomAttribute), false).FirstOrDefault() as MyCustomAttribute;
if(myCustomAttribute != null)
{
await writer.WriteAttributeStringAsync(null, "MyType", null, myCustomAttribute.MyType );
}
writer.WriteValue(value);
await writer.WriteEndElementAsync();
});
await writer.WriteEndElementAsync();
await writer.FlushAsync();
s.Position = 0;
doc.Load(s);
writer.Close();
}
string myXml = doc.OuterXml
In myXml should be something like that: (values are examples)
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Document MyType="word">something</Document>
<Time MyType="time">11:31:29</Time>
</Root>
You can do it in other way, of course. Here you have some docs which helped me: https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlwriter?view=netframework-4.8#writing_elements
Upvotes: 0
Reputation: 48255
Where do you have the type
stored?
Normally you could have something like:
class Document {
[XmlAttribute("type")]
public string Type { get; set; }
[XmlText]
public string Name { get; set; }
}
public class _Filter
{
[XmlElement("Times")]
public _Times Times;
[XmlElement("Document")]
public Document Document;
}
Upvotes: 63
Reputation: 1064204
It sounds like you need an extra class:
public class Document
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlText]
public string Name { get; set; }
}
Where an instance (in the example) would have Type = "word"
and Name = "document name"
; documents
would be a List<Document>
.
By the way - public fields are rarely a good idea...
Upvotes: 8
Reputation: 292725
The string
class doesn't have a type
property, so you can't use it to create the desired output. You should create a Document
class instead :
public class Document
{
[XmlText]
public string Name;
[XmlAttribute("type")]
public string Type;
}
And you should change the Document
property to type Document
Upvotes: 11