加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 基于文本树创建XML

发布时间:2020-12-16 01:59:48 所属栏目:百科 来源:网络整理
导读:我需要从这样的列表中去: /home/home/room1/home/room1/subroom/home/room2/home/room2/miniroom/home/room2/bigroom/home/room2/hugeroom/home/room3 到一个xml文件.我已经尝试使用LINQ to XML来做到这一点,但我最终感到困惑,不知道该怎么做.任何帮助深表
我需要从这样的列表中去:

/home
/home/room1
/home/room1/subroom
/home/room2
/home/room2/miniroom
/home/room2/bigroom
/home/room2/hugeroom
/home/room3

到一个xml文件.我已经尝试使用LINQ to XML来做到这一点,但我最终感到困惑,不知道该怎么做.任何帮助深表感谢!

编辑:

我希望XML文件看起来像这样:

<home>
   <room1>
      <subroom>This is a subroom</subroom>
   </room1>
   <room2>
      <miniroom>This is a miniroom</miniroom>
      <bigroom>This is a bigroom</bigroom>
      <hugeroom>This is a hugeroom</hugeroom>
   </room2>
   <room3></room3>
</home>

如果标签(“这是一个子房间等”)里面的文字是可选的,但是真的很棒!

解决方法

好的哥们,这是一个解决方案.

几个笔记和解释.

您的文本结构可以分成行,然后通过斜杠再次分成XML节点的名称.如果以这种方式考虑文本,就会得到一个列为“列”的“行”列表
名.

/home

首先,第一行/ home是XML的根;我们可以摆脱它,只需用该名称创建和XDocument对象作为根元素;

var xDoc = new XDocument("home");

当然我们不想硬编码,但这只是一个例子.现在,关于真正的工作:

/home/room1/
/home/room1/bigroom
etc...

作为列表< T>那么它会是这样的

myList = new List<List<string>>();
... [ add the items ]
myList[0][0] = home
myList[0][1] = room1

myList[1][0] = home
myList[1][1] = room1
myList[1][2] = bigroom

因此,我们可以做的是获得上述结构,多次使用string.Split()将文本首先分解为行,然后分成每行的部分,最后使用多维数组样式List< T>包含List< T>对象,在本例中为List< List< string>>.

首先让我们创建容器对象:

var possibleNodes = new List<List<string>>();

接下来,我们应该拆分线.让我们调用包含文本的变量“text”.

var splitLines = text
    .Split(new string[] { Environment.NewLine },StringSplitOptions.RemoveEmptyEntries)
    .ToList();

这给了我们一个列表,但我们的线路仍未分解.让我们用斜杠(/)字符再次拆分它们.这是我们构建节点名称的地方.我们可以在ForEach中执行此操作,只需添加到可能的节点列表中:

splitLines.ForEach(l => 
    possibleNodes.Add(l
        .Split(new char[] { '/' },StringSplitOptions.RemoveEmptyEntries)
        .ToList()
    )
);

现在,我们需要知道XML的DEPTH.您的文字显示将有3个深度节点.节点深度是任何一个给定节点行的最大深度,现在存储在List< List< string>&gt ;;我们可以使用.Max()方法来获取:

var nodeDepth = possibleNodes.Max(n => n.Count);

最后的设置步骤:我们不需要第一行,因为它只是“home”,它将是我们的根节点.我们可以创建一个XDocument对象并将其作为第一行用作Root的名称:

// Create the root node
XDocument xDoc = new XDocument(new XElement(possibleNodes[0][0]));

// We don't need it anymore
possibleNodes.RemoveAt(0);

好的,这是实际工作发生的地方,让我解释一下规则:

>我们需要循环遍历外部列表,并遍历每个内部列表.
>我们可以使用列表索引来了解要添加的节点或要忽略的名称
>我们需要保持层次结构正确而不是重复节点,并且一些XLinq在这里有所帮助

循环 – 请参阅注释以获取详细说明:

// This gets us looping through the outer nodes
for (var i = 0; i < possibleNodes.Count; i++) 
{
    // Here we go "sideways" by going through each inner list (each broken down line of the text)
    for (var ii = 1; ii < nodeDepth; ii++)
    {
        // Some lines have more depth than others,so we have to check this here since we are looping on the maximum
        if (ii < possibleNodes[i].Count)
        {
            // Let's see if this node already exists
            var existingNode = xDoc.Root.Descendants().FirstOrDefault(d => d.Name.LocalName == (possibleNodes[i][ii]));

            // Let's also see if a parent node was created in the previous loop iteration. 
            // This will tell us whether to add the current node at the root level,or under another node
            var parentNode = xDoc.Root.Descendants().FirstOrDefault(d => d.Name.LocalName == (possibleNodes[i][ii - 1]));

            // If the current node has already been added,we do nothing (this if statement is not entered into)
            // Otherwise,existingNode will be null and that means we need to add the current node
            if (null == existingNode)
            {
                // Now,use parentNode to decide where to add the current node
                if (null == parentNode)
                {
                    // The parent node does not exist; therefore,the current node will be added to the root node.
                    xDoc.Root.Add(new XElement(possibleNodes[i][ii]));
                }
                else
                {
                    // There IS a parent node for this node! 
                    // Therefore,we must add the current node to the parent node 
                    // (remember,parent node is the previous iteration of the inner for loop on nodeDepth )
                    var newNode = new XElement(possibleNodes[i][ii]);
                    parentNode.Add(newNode);

                    // Add "this is a" text (bonus!) -- only adding this text if the current node is the last one in the list.
                    if (possibleNodes[i].Count -1 == ii)
                    {
                        newNode.Add(new XText("This is a " + newNode.Name.LocalName));
                    }
                }
            }
        }
    }
}

这里的优点是此代码可以与任意数量的节点一起使用并构建您的XML.

为了检查它,XDocument有一个漂亮的.ToString()覆盖实现,只是吐出它所持有的所有XML,所以你要做的就是:

Console.Write(xDoc.ToString());

而且,你会得到这个结果:
(注意我添加了一个测试节点,以确保它适用于超过3个级别)

下面,您将找到包含测试文本等的整个程序,作为一个有效的解决方案:

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

namespace XmlFromTextString
{
    class Program
    {
        static void Main(string[] args)
        {
            // This simulates text from a file; note that it must be flush to the left of the screen or else the extra spaces 
            // add unneeded nodes to the lists that are generated; for simplicity of code,I chose not to implement clean-up of that and just 
            // ensure that the string literal is not indented from the left of the Visual Studio screen.
            string text =
@"/home
/home/room1
/home/room1/subroom
/home/room2
/home/room2/miniroom
/home/room2/test/thetest
/home/room2/bigroom
/home/room2/hugeroom
/home/room3";

            var possibleNodes = new List<List<string>>();

            var splitLines = text
                .Split(new string[] { Environment.NewLine },StringSplitOptions.RemoveEmptyEntries)
                .ToList();

            splitLines.ForEach(l => 
                possibleNodes.Add(l
                    .Split(new char[] { '/' },StringSplitOptions.RemoveEmptyEntries)
                    .ToList()
                )
            );

            var nodeDepth = possibleNodes.Max(n => n.Count);

            // Create the root node
            XDocument xDoc = new XDocument(new XElement(possibleNodes[0][0]));

            // We don't need it anymore
            possibleNodes.RemoveAt(0);

            // This gets us looping through the outer nodes
            for (var i = 0; i < possibleNodes.Count; i++)  
            {
                // Here we go "sideways" by going through each inner list (each broken down line of the text)
                for (var ii = 1; ii < nodeDepth; ii++)
                {
                    // Some lines have more depth than others,so we have to check this here since we are looping on the maximum
                    if (ii < possibleNodes[i].Count)
                    {
                        // Let's see if this node already exists
                        var existingNode = xDoc.Root.Descendants().FirstOrDefault(d => d.Name.LocalName == (possibleNodes[i][ii]));

                        // Let's also see if a parent node was created in the previous loop iteration. 
                        // This will tell us whether to add the current node at the root level,or under another node
                        var parentNode = xDoc.Root.Descendants().FirstOrDefault(d => d.Name.LocalName == (possibleNodes[i][ii - 1]));

                        // If the current node has already been added,we do nothing (this if statement is not entered into)
                        // Otherwise,existingNode will be null and that means we need to add the current node
                        if (null == existingNode)
                        {
                            // Now,use parentNode to decide where to add the current node
                            if (null == parentNode)
                            {
                                // The parent node does not exist; therefore,the current node will be added to the root node.
                                xDoc.Root.Add(new XElement(possibleNodes[i][ii]));
                            }
                            else
                            {
                                // There IS a parent node for this node! 
                                // Therefore,we must add the current node to the parent node 
                                // (remember,parent node is the previous iteration of the inner for loop on nodeDepth )
                                var newNode = new XElement(possibleNodes[i][ii]);
                                parentNode.Add(newNode);

                                // Add "this is a" text (bonus!) -- only adding this text if the current node is the last one in the list.
                                if (possibleNodes[i].Count -1 == ii)
                                {
                                    newNode.Add(new XText("This is a " + newNode.Name.LocalName));
                                    // For the same default text on all child-less nodes,us this:
                                    // newNode.Add(new XText("This is default text"));

                                }
                            }
                        }
                    }
                }
            }

            Console.Write(xDoc.ToString());
            Console.ReadKey();
        }
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读