Home > OS >  How to generate tags inside another tag in XML c#?
How to generate tags inside another tag in XML c#?

Time:05-12

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>&lt;en&gt;This is English Languages description 
 &lt;/en&gt;&lt;fr&gt;&lt;/fr&gt;</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.

CodePudding user response:

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.

CodePudding user response:

Using Xml Linq :

           string header = "<root></root>";
            XDocument doc = XDocument.Parse(header);

            XElement root = doc.Root;

            root.Add( new XElement("property", new object[] {
                new XElement("languages", new object[] {
                    new XElement("en", "This is English Languages description"),
                    new XElement("fr")
                })
            }));

        }
  • Related