gpt4 book ai didi

c# - 基于文本树创建 XML

转载 作者:数据小太阳 更新时间:2023-10-29 02:20:38 27 4
gpt4 key购买 nike

我需要从这样的列表中选择:

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

作为 List<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>>();

接下来,我们应该分割线。我们将保存文本的变量称为“文本”。

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 的深度。您的文字显示将有 3 个深度节点。节点深度是任何给定节点行的最大深度,现在存储在 List<List<string>> 中。 ;我们可以使用 .Max()获取方法:

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

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

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

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

好吧,这里是真正的工作发生的地方,让我解释一下规则:

  1. 我们需要遍历外部列表和每个内部列表。
  2. 我们可以使用列表索引来了解要添加到哪个节点或要忽略哪些名称
  3. 我们需要保持正确的层次结构而不是重复的节点,一些 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 个级别)

enter image description here

在下面,您将找到整个程序以及您的测试文本等作为可行的解决方案:

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

关于c# - 基于文本树创建 XML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21490330/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com