INI在C#中将平面文本文件输入到XML

时间:2016-02-26 08:12:08

标签: c# xml linq-to-xml

我有一个包含以下行的文本文件:

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

我想得到什么:

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

所以我想将不同长度的行转换为XML节点,然后将它们合并到C#中的单个XML文件中。
我读到了LINQtoXML,但我还是新手。

请帮忙。

这就是我现在的位置:

        // 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");

这是我想要的第一部分。

输出现在是这样的:

<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>

现在我想将这些节点合并到我首先描述的格式中。

感谢您的帮助。 :)

3 个答案:

答案 0 :(得分:1)

试试这个,

        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]));
                        }
                    }
                }
            }

可行的解决方案:.NET Fiddle

答案 1 :(得分:0)

您好请查看此链接,该链接对您的搜索内容非常有用

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

答案 2 :(得分:0)

还有一个实现:

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;

            }
        }
    }
}

输出:

<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>