czondi
czondi

Reputation: 13

INI type flat text file to XML in C#

I have a text file with the following lines:

root_node1_node2_node3=value  
root_node1_node2_node3=value  
root_node1_node2_node3_node4=value  
root_node5_node6=value  

What I would like to get:

<root>
  <node1>
    <node2>
      <node3>value</node3>
      <node3>value</node3>
      <node3>
        <node4>value</node4>
      </node3>
    </node2>
  </node1>
  <node5>
    <node6>value</node6>
  </node5>
</root>

So I would like to convert the lines of varied lengths to XML nodes, then merge them to a single XML file in C#.
I read about LINQtoXML but I'm still new to it.

Please help.


This is where I am now:

        // file
        string fileName = Path.GetFileName(file);
        string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
        string fileSourceDirectory = Path.GetDirectoryName(file);

        // xml
        XDocument xDoc = new XDocument(
            new XDeclaration("1.0", "utf-8", null),
            // root
            new XElement(fileNameWithoutExtension)
            );

        try
        {
            using(StreamReader sr = new StreamReader(file))
            {
                string line;

                // go line-by-line
                while((line = sr.ReadLine()) != null)
                {

                    Console.WriteLine(line);

                    // element=value -> [element, value]
                    string[] elementAndValue = line.Split('=');
                    // elment_element_element -> [element, elelement, element]
                    string[] elements = elementAndValue[0].Split('_');
                    // value
                    string value = elementAndValue[1];

                    List<XElement> elementList = new List<XElement>();

                    for(int i = 0; i < elements.Length; i++)
                    {
                        if(i == (elements.Length - 1))
                        {
                            elementList.Add(new XElement(elements[i], value));
                            Console.WriteLine("Added: " + elements[i] + "=" + value);
                        }
                        else
                        {
                            elementList.Add(new XElement(elements[i]));
                            Console.WriteLine("Added: " + elements[i]);
                        }
                    }

                    xDoc.Root.Add(elementList[0]);
                    Console.WriteLine("Added first item to root.");

                    for(int i = 0; i < elementList.Count - 1; i++)
                    {
                        elementList[i].Add(elementList[i + 1]);
                        Console.WriteLine("Added " + elementList[i + 1] + " to " + elementList[i]);
                    }

                }
            }
        }
        catch(Exception e)
        {
            Console.WriteLine(e.Message);
        }

        // save xml
        xDoc.Save(outputDir + "\\" + fileNameWithoutExtension + ".xml");

This does the first part what I wanted.

The output is something like this now:

<root>
  <node1>
    <node2>
      <node3>value</node3>
    </node2>
  </node1>
  <node1>
    <node2>
      <node3>value</node3>
    </node2>
  </node1>
  <node1>
    <node2>
      <node3>
        <node4>value</node4>
      </node3>
    </node2>
  </node1>
  <node5>
    <node6>value</node6>
  </node5>
</root>

Now I would like to merge these nodes to the format which I described the first place.

Thank you for any help. :)

Upvotes: 1

Views: 577

Answers (3)

valex
valex

Reputation: 24144

One more implementation:

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

namespace Ini2XML
{
    class Program
    {
        static void Main(string[] args)
        {

            string[] lines = new string[] {
            "root_node1_node2_node3 = value",
            "root_node1_node2_node3 = value1",
            "root_node1_node2_node3_node4 = value",
            "root_node5_node6 = value",
            "root_node5_node6_node7_node8_node8 = value",
            "root_node55 = value2 2232 2 232 2 2 "
           };

            XDocument xml = Ini2XMLConverter.ConvertStringArrayToXML(lines);
            xml.Save(Console.Out);

        }

        public class Ini2XMLConverter
        {
            public static XDocument ConvertStringArrayToXML(IEnumerable<string> lines)
            {
                if (lines == null) { return null; };

                XDocument xml = new XDocument();
                foreach (string s in lines)
                {
                    //define path and value from each line
                    string[] sp = s.Split('=');

                    string[] path = sp[0].Trim().Split('_');
                    string value = sp[1].Trim();

                    //node to attach the current node
                    XElement attachTo = null;

                    for (int i = 0; i < path.Length; i++)
                    {
                        XElement currentNode = null;

                        if (i == path.Length - 1)
                        {  //last node it's a TEXT node with value after "="
                            currentNode = new XElement(path[i], value);
                        }
                        else
                        {   //a simple node in the middle
                            currentNode = new XElement(path[i]);
                        }

                        // adding the root
                        if (xml.Root == null)
                        {
                            xml.Add(currentNode);
                            attachTo = currentNode;
                            continue;
                        }
                        else if (attachTo == null)
                        {   //If it's a root then the first elements have to be the same 
                            attachTo = xml.Root;
                            continue;
                        }

                        //looking for the same name node
                        XElement f = attachTo.Descendants(currentNode.Name).Count() == 0 ? null : attachTo.Descendants(currentNode.Name).First();

                        //skip elements with TEXT values 
                        if ((f != null) && (f.LastNode != null) && (f.LastNode.NodeType == System.Xml.XmlNodeType.Text)) { f = null; }

                        if (f == null)
                        {
                            //add new node
                            attachTo.Add(currentNode);
                            attachTo = currentNode;
                        }
                        else
                        {   //don't add node if it exists already. Just move pointer to it.
                            attachTo = f;
                        }

                    }
                }
                return xml;

            }
        }
    }
}

Output:

<root>
  <node1>
    <node2>
      <node3>value</node3>
      <node3>value1</node3>
      <node3>
        <node4>value</node4>
      </node3>
    </node2>
  </node1>
  <node5>
    <node6>value</node6>
    <node6>
      <node7>
        <node8>
          <node8>value</node8>
        </node8>
      </node7>
    </node6>
  </node5>
  <node55>value2 2232 2 232 2 2</node55>
</root>

Upvotes: 0

codeninja.sj
codeninja.sj

Reputation: 4119

try this,

        XDocument xDoc = new XDocument();  

        while ((line = sr.ReadLine()) != null)
        {
            string[] nodes = line.Split('_');               
            for (int j = 0; j < nodes.Length; j++)
            {
                if(j == 0) // assume that all line should start with same root name
                {
                    if (xDoc.Root == null)
                    {
                        var root = new XElement(nodes[j]);
                        xDoc.Add(root);
                    }
                }
                else
                {
                    var previousNode = xDoc.Descendants(nodes[j - 1]).FirstOrDefault();
                    if (nodes[j].Contains('='))
                    {
                        var elementValues = nodes[j].Split('=');

                        if (previousNode.DescendantNodes().Count() == 1 && previousNode.Value != "")
                        {
                            previousNode.AddAfterSelf(new XElement(nodes[j - 1], new XElement(elementValues[0], elementValues[1])));                                    
                        }
                        else
                        {
                            previousNode.Add(new XElement(elementValues[0], elementValues[1]));
                        }
                    }
                    else
                    {
                        var node = xDoc.Descendants(nodes[j]);                            
                        if (node.Count() == 0)
                        {
                            previousNode.Add(new XElement(nodes[j]));
                        }
                    }
                }
            }

Workable solution : .NET Fiddle

Upvotes: 1

Rahul Bhat
Rahul Bhat

Reputation: 41

Hi Please check this link which is useful for what your looking for

http://www.dreamincode.net/forums/topic/218979-linq-to-xml/

Upvotes: 0

Related Questions