问题:
我一直在尝试解析 xml,并为 XML 中的每个节点创建一个对象。
问题:
由于我的 xml 具有任意顺序的节点,并且有些节点是其他节点的子节点,因此我很难在不使用 .net 1.1 和 XmlNode 类的情况下从逻辑上解析它们。
注意:我希望只使用 XMLReader,因为我仅限于 .Net Standard 1.0,并且不想安装任何额外的库。 (参见此处:https://learn.microsoft.com/en-us/dotnet/standard/net-standard)
目前我为每个 xml 节点创建一个对象,每个对象包含一个我希望添加到的子组件列表,如果它找到一个子节点。但是我似乎无法递归搜索 xml 并将结构正确生成到列表/列表列表中。
我的代码:
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApp1
{
class Program
{
static List<UIComponent> components = new List<UIComponent>();
static void Main(string[] args)
{
String path = "C:\\Users\\admin\\Desktop\\test.xml";
parseXML(path);
}
private static UIComponent addToLowestChild(UIComponent parent, UIComponent child)
{
for(int i=0;i<parent.getChildren().Count;++i)
{
if (parent.getChildren().Count > 0)
{
foreach (UIComponent kid1 in parent.getChildren())
{
if (kid1.getChildren().Count > 0)
{
addToLowestChild(kid1, child);
}
}
}
}
return parent;
}
private static UIComponent ChildTest(int depth,UIComponent parent,UIComponent child)
{
//i=depth for item 4, if i is set to 1 first
for (int i = 1; i < depth; ++i)
{
if (parent.getChildren().Count > 0)
{
if (i > 1)
{
ChildTest(i, parent.getChildren()[parent.getChildren().Count - 1], child);
}
else
{
parent.getChildren()[parent.getChildren().Count - 1].addChild(child);
break;
}
}
else
{
parent.addChild(child);
break;
}
}
return parent;
}
private static void parseXML(string path)
{
//read the xml file into one string
string[] lines = System.IO.File.ReadAllLines(path);
string xmlContent = "";
foreach (string line in lines)
{
xmlContent += line;
}
UIComponent currentComponent = null;
//parse the xml content
using (XmlReader reader = XmlReader.Create(new StringReader(xmlContent)))
{
while (reader.Read())
{
int currentDepth = 0;
// Console.WriteLine(reader.Name+" depth:"+reader.Depth);
if (reader.Depth > 0) //ignore ground level elements such as <XML> and <UI>
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (currentComponent == null || reader.Depth==currentDepth)
{
currentComponent = new UIComponent(reader.Name);
}
else
{
UIComponent childComponent = new UIComponent(reader.Name);
//currentComponent.addChild(childComponent);
ChildTest(reader.Depth,currentComponent,childComponent);
}
break;
case XmlNodeType.Text:
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
break;
case XmlNodeType.Comment:
break;
case XmlNodeType.EndElement:
if (reader.Depth == 1 && currentComponent!=null)
{
components.Add(currentComponent);
currentComponent = null;
}
break;
default: break;
}
}
}
}
}
我的测试数据
<?xml version="1.0" encoding="UTF-8"?>
<UI>
<window x="5">
<Button2 value="">
<Button3 y="">
</Button3>
<Button4>
<Button6 value=""></Button6>
<Button5 value=""></Button5>
</Button4>
</Button2>
</window>
<window></window>
<heading></heading>
</UI>
输出:
-Window
|-Button 2
|-- Button 3
|-- Button 4
|-- Button 6
|-- Button 5
-Window
-Heading
我想要的:
-Window
|-Button 2
|-- Button 3
|-- Button 4
|-- Button 6
|-- Button 5
-Window
-Heading
最佳答案
您只需要维护一个当前正在处理的节点的堆栈。任何时候你点击 StartElement
,您创建一个新节点,读取属性,将其添加到父节点或根节点列表,如果它不是空元素(如 <window />
),则将其插入堆栈。当你点击 EndElement
您只需弹出(删除)堆栈的最后一个元素。栈顶元素代表当前正在处理的节点。
将其付诸实践,将 XML 解析为像这样的简单类列表:
class Node
{
public string Name;
public List<Node> Children = new List<Node>();
public Dictionary<string, string> Attributes = new Dictionary<string, string>();
public override string ToString() => Name;
}
可能是这样的:
static List<Node> ParseXML(string xmlContent)
{
using (var reader = XmlReader.Create(new StringReader(xmlContent)))
{
var rootNodes = new List<Node>();
var nodeStack = new Stack<Node>();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
var node = new Node { Name = reader.Name };
if (reader.MoveToFirstAttribute())
{
// Read the attributes
do
{
node.Attributes.Add(reader.Name, reader.Value);
}
while (reader.MoveToNextAttribute());
// Move back to element
reader.MoveToElement();
}
var nodes = nodeStack.Count > 0 ? nodeStack.Peek().Children : rootNodes;
nodes.Add(node);
if (!reader.IsEmptyElement)
nodeStack.Push(node);
break;
case XmlNodeType.EndElement:
nodeStack.Pop();
break;
}
}
return rootNodes;
}
关于c# - 将 XML 结构重建为递归样式列表/XMLReader 替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46073941/