I have a class file like below :
public class property : root
{
public string languages { get; set; }
}
I am trying to generate xml
like below :
Final Output:
<root>
<property>
--other properties
<languages>
<en>This is English Languages description</en>
<fr></fr>
</languages>
</property>
</root>
This is how I am trying to generate the <languages>
tag :
private string GenerateLanguageTag(IList<Languages> languages)
{
string lang = string.Empty;
foreach (var item in languages)
{
lang += "<" + item.IsoLanguageCode + ">" + item.Description + "</" + item.IsoLanguageCode + ">";
}
return lang;
}
output:
<root>
<property>
--other properties
<languages><en>This is English Languages description
</en><fr></fr></languages>
</property>
</root>
Code:
root root = GetData(data);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(root));
using (StringWriter xmlWriter = new StringWriter())
{
xmlSerializer.Serialize(xmlWriter, root);
value = xmlWriter.ToString();
value = value.Replace(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", "");
value = value.Replace(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"", "");
value = value.Replace("utf-16", "ISO-8859-1");
if (File.Exists(filePath))
{
var document = XDocument.Parse(value);
document.Save(filePath);
}
}
Update:
Tags "en", "fr"
and many other languages inside <languages></languages>
are generated dynamically based on the languages we have in the database.
Rather than declaring languages
as a string
, declare it as an XElement
and mark it with [XmlAnyElement("languages")]
. This informs the serializer that the children of the languages
property should be inserted as children of their parent <property>
element. Thus your data model should look like:
public class root
{
public property property { get; set; }
}
public class property
{
[XmlAnyElement("languages")]
public XElement languages { get; set; }
}
And you would construct your model as follows:
// Your dynamic list of languages & values
var languages = new List<(string IsoLanguageCode, string Description)>
{
("en", "This is English Languages description"),
("fr", ""),
};
var root = new root()
{
property = new()
{
languages = new XElement("languages", languages.Select(l => new XElement(l.IsoLanguageCode, l.Description))),
},
};
Notes:
The documentation for XmlAnyElementAttribute
indicates it should be applied to properties of type XmlElement
or XmlNode
(or arrays of the same), but in fact it works for properties of type XElement
as well. Since LINQ-to-XML is easier to work with than the old XmlDocument
API, I suggest using it instead.
In your question you show property
as a subclass of root
. In order to get the nesting you require, it should be a separate class contained by root
, not a subclass of root
.
To eliminate the xsi
and xsd
namespaces (without needing to do a string replacement) see XmlSerializer: remove unnecessary xsi and xsd namespaces.
Demo fiddle here.