c# – 基于文本树创建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>> ;;我们可以使用.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); 好的,这是实际工作发生的地方,让我解释一下规则: >我们需要循环遍历外部列表,并遍历每个内部列表. 循环 – 请参阅注释以获取详细说明: // 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()); 而且,你会得到这个结果: 下面,您将找到包含测试文本等的整个程序,作为一个有效的解决方案: 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(); } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |