0

I trying to find an "elegant way" to add/modify some XML Elements in the XML produced from the DataTable.WriteXML

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
  <Documents>
    <XMLelement1>Value1</XMLelement1>
    <XMLelement2>Value2</XMLelement2>
    <XMLelement3>Value3</XMLelement3>
  </Documents>
</DocumentElement>

But i want something like this

   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <SomeGroupElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <SomeGroupElement2 XMLElementA="ABCD" XMLElementB="123" XMLElementC="XYZ" XMLElementD="1">
            <SomeGroupElement2 XMLElementZ="KLM">
                <Grouping>
                    <XMLelement1>Value1</XMLelement1>
        <XMLelement2>Value2</XMLelement2>
        <XMLelement3>Value3</XMLelement3>
</Grouping>
</SomeGroupElement2>
</SomeGroupElement>

I have done some tests with XSLT and adding Elements on the fly ...and also by using the GetXML to get the string and manipulate it as a string by i feel there should be some better way.
P.S. XMLelement1,XMLelement2,XMLelement3 are fields of the DataTable/ along with their values.
P.S.2 I am pretty sure i am not using XML terminology correctly, sorry for that.

John
  • 974
  • 8
  • 16
  • 1
    Have you tried [LINQ to XML](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/linq-to-xml-overview)? – nosale Dec 11 '18 at 17:58
  • First, you need to load your XML to XElement: `using (var ms = new MemoryStream()) { dataTable.WriteXml(ms); ms.Position = 0L; var xml = XElement.Load(ms); }` – JohnyL Dec 11 '18 at 18:00
  • I have seen this technique of loading a XML into a MemoryStream in order to avoid the I/O but i haven't found the "after" – John Dec 11 '18 at 18:09
  • You could serialize your `DataTable` directly to an `XElement` using, say, the static methods from [this answer](https://stackoverflow.com/a/29352446) or [this one](https://stackoverflow.com/a/30562461), then add the additional elements using LINQ to XML. This avoids any string manipulation or parsing. – dbc Dec 11 '18 at 18:10

1 Answers1

0

You want to add additional items to existing xml file. My first solution is wrapping the existing items into a DataSet. Your method is adding new elements in the leaves. Both end up with similar xml files

I would create a DatatSet that contains a separate table for each grouping. From a datatable you can create new datatable as shown below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;


namespace ConsoleApplication92
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            //source datatable
            DataTable dt = new DataTable();

            var groups = dt.AsEnumerable().GroupBy(x => new { a = x.Field<string>("ColumnA"), b = x.Field<string>("ColumnB"), c = x.Field<string>("ColumnC") }).ToList();

            DataSet ds = new DataSet();

            foreach(var group in groups)
            {
                DataTable newDt = group.CopyToDataTable();
                dt.TableName = string.Join("_", new object[] { group.Key.a, group.Key.b, group.Key.c });
                ds.Tables.Add(newDt);
            }

            ds.WriteXml(FILENAME, XmlWriteMode.WriteSchema);

        }
    }
}

Method 2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication91
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {

            XDocument doc = XDocument.Load(FILENAME);

            XElement documents = doc.Descendants("Documents").FirstOrDefault();

            XElement groupElement = new XElement("SomeGroupElement2", new object[] {
                new XAttribute("XMLElementA","ABCD"),
                new XAttribute("XMLElementB","123"),
                new XAttribute("XMLElementC","XYZ"),
                new XAttribute("XMLElementD","1")
            });

            documents.ReplaceWith(groupElement);
            XElement grouping = new XElement("Grouping");
            groupElement.Add(grouping);

            for(int i = 1; i <= 3; i++)
            {
                XElement newXElement = new XElement("XMLelement" + i.ToString(), "Value" + i.ToString());
                grouping.Add(newXElement);
            }

        }
    }

}
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Well this would be great if it was a complex XML ...its pretty straightforward...just replace the grouping "Documents" with "Grouping", replace the "DocumentElement" with "SomeGroupElement2 " and just add the elements above...thanks anyway for your answer. – John Dec 11 '18 at 18:35
  • Well it is elegant!!! It isn't obvious from what you posted to do what you just described in the comment. I will follow exactly what you comments says tomorrow morning. – jdweng Dec 12 '18 at 01:57
  • I added new xml to existed solution. You want to add additional items to existing xml file. My first solution is wrapping the existing items into a DataSet. Your method is adding new elements in the leaves. Both end up with similar xml files but mine is more elegant!!! – jdweng Dec 12 '18 at 10:23
  • Well the groupElement seems cool but it replaces the rest of the Documents...i want this to become the parent of documents – John Dec 12 '18 at 10:48
  • It is still part of doc. I followed your expected xml you posted. – jdweng Dec 12 '18 at 10:49
  • Well with documents.Remove(); SomeGroupElement2.Add(documents); xdoc.Add(SomeGroupElement2); i got to the point i wanted...all is left is the start document " " – John Dec 12 '18 at 11:16
  • I usually stat new document like this : string xml = ""; XDocument doc = XDocument.Parse(xml); – jdweng Dec 12 '18 at 11:33
  • i just found it var decl = new XDeclaration("1.0", "utf-8", "true"); xdoc.Declaration = decl; – John Dec 12 '18 at 11:43