0

I have these classes:

public class WikiEntry
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    [XmlArray]
    public List<Category> Categories { get; set; }
}

public class Category
{
    [XmlAttribute]
    public string Id { get; set; }
    [XmlAttribute]
    public string Text { get; set; }
}

At the beginning I have this XML structure:

<Wiki>
  <Categories></Categories>
  <Tags></Tags>
  <WikiEntries></WikiEntries>
</Wiki>

And I am serializing wiki.Categories and adding it into the existing XML like this:

var xDoc = XDocument.Load("Data.xml");

WikiEntry wiki = new WikiEntry
{
   Id = Guid.NewGuid().ToString(),
   Title = "Simple title",
   Content = "Simple content here",
   Categories = new List<Category>
     {
       new Category
       {
         Id = Guid.NewGuid().ToString(),
         Text = "CATEGORYA"
       },
       new Category
       {
         Id = Guid.NewGuid().ToString(),
         Text = "CATEGORYB"
       }
    }
};

var categories = xDoc.Root.Element("Categories");

var categoriesBuilder = new StringBuilder();

using (var writer = XmlWriter.Create(categoriesBuilder, new XmlWriterSettings { Indent = true, ConformanceLevel = ConformanceLevel.Auto, OmitXmlDeclaration = true }))
        {
            var ns = new XmlSerializerNamespaces();
            ns.Add("", "");

            var xs = new XmlSerializer(typeof(List<Category>), "");

            xs.Serialize(writer, wiki.Categories, ns);
        }

categories.Add(XElement.Parse(categoriesBuilder.ToString().Trim()));
xDoc.Save(file);

The problem is that when I do I get this:

<Categories>
 <ArrayOfCategory>
   <Category Id="482ce9f6-5d4c-48f9-b84f-33c3cf9b0b0f" Text="CATEGORYA" />
   <Category Id="73e6c671-fb6d-40a4-8694-1d5dbcf381d5" Text="CATEGORYB" />
 </ArrayOfCategory>
 <ArrayOfCategory>
   <Category Id="3c0f2a15-4623-4f33-b356-75e8c8b89624" Text="CATEGORYA" />
   <Category Id="d8720ca9-06f5-401d-90e2-c7f43e1c91f5" Text="CATEGORYB" />
 </ArrayOfCategory>

So, my question is how can I serialize my Category class , so that I get this (omitting the <ArrayOfCategory> parent):

  <Categories>
      <Category Id="482ce9f6-5d4c-48f9-b84f-33c3cf9b0b0f" Text="CATEGORYA" />
      <Category Id="73e6c671-fb6d-40a4-8694-1d5dbcf381d5" Text="CATEGORYB" />
      <Category Id="3c0f2a15-4623-4f33-b356-75e8c8b89624" Text="CATEGORYA" />
      <Category Id="d8720ca9-06f5-401d-90e2-c7f43e1c91f5" Text="CATEGORYB" />
  </Categories>

Note: I want to remove it, not rename it.

5
  • Can you post your complete code include how categoriesBuilder and wikis are being instantiated? Commented Aug 31, 2018 at 4:37
  • You forgot to show how xDoc is being instantiated. Commented Aug 31, 2018 at 5:46
  • Done. Thanks for catching that. Commented Aug 31, 2018 at 7:30
  • Added response as answer. Commented Aug 31, 2018 at 15:51
  • Are you looking for Deserializing into a List without a container element in XML? Commented Sep 1, 2018 at 18:30

3 Answers 3

1

You can serialize directly into an XDocument by using XContainer.CreateWriter(). This in turn will allow you to serialize directly into a child XElement of your categories element without any intermediate string representation.

First, define the following extension method:

public static class XObjectExtensions
{
    public static XElement SerializeToXElement<T>(this T obj, XContainer parent = null, XmlSerializer serializer = null, XmlSerializerNamespaces ns = null)
    {
        if (obj == null)
            throw new ArgumentNullException();
        // Initially, write to a fresh XDocument to cleanly avoid the exception described in
        // https://stackoverflow.com/questions/19045921/net-xmlserialize-throws-writestartdocument-cannot-be-called-on-writers-created
        var doc = new XDocument();
        using (var writer = doc.CreateWriter())
        {
            (serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns ?? NoStandardXmlNamespaces());
        }
        // Now move to the incoming parent.
        var element = doc.Root;
        if (element != null)
        {
            element.Remove();
            if (parent != null)
            {
                parent.Add(element);
            }
        }
        return element;
    }

    public static XmlSerializerNamespaces NoStandardXmlNamespaces()
    {
        var ns = new XmlSerializerNamespaces();
        ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
        return ns;
    }
}

Now you can add the Categories of your WikiEntry to your xDoc as follows:

var categories = xDoc.Root.Element("Categories");
foreach (var category in wiki.Categories)
{
    category.SerializeToXElement(categories);
}

Working sample .Net fiddle here.

Sign up to request clarification or add additional context in comments.

Comments

0

Passing the root name as argument to the XMLSerializer call can do the trick.

XmlSerializer serializer = new XmlSerializer(typeof(List), new XmlRootAttribute("RootElementName"));

1 Comment

Clever, but no, it just makes inner element the same name as the outer, parent node, like so <Categories><Categories><Category></Category</Categories></Categories>
0

Here is some Linq-to-Xml to achieve what you are looking for:

categories.Add(XElement.Parse(categoriesBuilder.ToString().Trim()));


XDocument output =
new XDocument(
    new XElement(xDoc.Root.Name,
        new XElement("Categories",
            from comp in xDoc.Root.Elements("Categories").Elements("ArrayOfCategory").Elements("Category")
            select new XElement("Category",
                new XAttribute("Id", comp.Attribute("Id").Value),
                new XAttribute("Text", comp.Attribute("Text").Value)
            ))));




output.Save("c:\\so\\test.xml");

4 Comments

Does the solution address your needs?
I've already used LINQ-to-XML, but wasn't what I was looking for. Still, thanks for the suggestion!
No problem, although it's impossible to think why this would not work for you. Next time be specific in your question if you are avoiding a solution so people here aren't wasting time trying to help you with something you dont need.
I am not "avoiding" a solution. I was specific enough for @dbc to actually help me solve my problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.