使用Linq to XML创建深层对象图,重构?
-
06-07-2019 - |
题
我正在使用LINQ to XML编写一个简单的XML文件解析器。
我希望为XML中的每个元素提供一个TreeNode对象(即一个简单的Tree结构)。我希望每个元素都是强类型的。
与之前使用的简单循环方法(使用System.XML)相比,它看起来很丑陋和冗余。有没有办法去除这里的裁员?
XElement ops = XElement.Load(@"c:\temp\exp.xml");
Tree<Element> domain = new Tree<Element>();
domain.Root = new TreeNode<Element>();
var cells =
from cell in ops.Elements("cell")
select new
{
TreeNodeObj = new TreeNode<Element>
(new Cell((string)cell.Attribute("name"), (string)cell.Attribute("name"), null)),
XElem = cell
};
foreach (var cell in cells)
{
domain.Root.AddChild(cell.TreeNodeObj);
var agents =
from agent in cell.XElem.Elements("agent")
select new
{
TreeNodeObj = new TreeNode<Element>
(new Agent((string)agent.Attribute("name"), (string)agent.Attribute("name"), null)),
XElem = agent
};
foreach (var agent in agents)
{
cell.TreeNodeObj.AddChild(agent.TreeNodeObj);
var nas =
from na in agent.XElem.Elements("node-agent")
select new
{
TreeNodeObj = new TreeNode<Element>
(new NodeAgent((string)na.Attribute("name"), (string)na.Attribute("name"), null)),
XElem = agent
};
foreach (var na in nas)
{
agent.TreeNodeObj.AddChild(na.TreeNodeObj);
}
}
}
解决方案
如果没有样本数据和实际类型,很难完全回答这个问题,但我会像下面那样重构它。
从最初的例子中,我假设我们不想搞乱实体的构造函数(Agent
etc),并且我们想要保留单独的<!> quot; TreeNode<T>
<! > QUOT;模型,将我们的实体放在树中(而不是更改实体以将事物建模为关联集合)。我还假设我们可以使用IEnumerable<...>
获得比实体更多的自由,所以我引入了一个接受<=>的构造函数,因为这允许使用LINQ子查询:
XElement ops = XElement.Load(@"c:\temp\exp.xml");
Tree<Element> domain = new Tree<Element>(
from cell in ops.Elements("cell")
select new TreeNode<Element>(
new Cell(
(string)cell.Attribute("name"),
(string)cell.Attribute("name"), null
),
from agent in cell.Elements("agent")
select new TreeNode<Element>(
new Agent(
(string)agent.Attribute("name"),
(string)agent.Attribute("name"), null
),
from na in agent.Elements("node-agent")
select new TreeNode<Element>(
new NodeAgent(
(string)na.Attribute("name"),
(string)na.Attribute("name"), null
)
)
)
)
);
使用以下框架代码:
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
class Tree<T>
{
public TreeNode<T> Root { get; set; }
public Tree() { }
public Tree(IEnumerable<TreeNode<T>> children)
{
Root = new TreeNode<T>(children);
}
}
class TreeNode<T>
{
private List<TreeNode<T>> children;
public IList<TreeNode<T>> Children
{
get
{
if (children == null) children = new List<TreeNode<T>>();
return children;
}
}
private readonly T value;
public TreeNode() { }
public TreeNode(T value) { this.value = value; }
public TreeNode(T value, IEnumerable<TreeNode<T>> children)
: this(children)
{
this.value = value;
}
public TreeNode(IEnumerable<TreeNode<T>> children)
{
children = new List<TreeNode<T>>(children);
}
}
class Element { }
class Cell : Element {
public Cell(string x, string y, string z) { }
}
class Agent : Element {
public Agent(string x, string y, string z) { }
}
class NodeAgent : Element {
public NodeAgent(string x, string y, string z) { }
}
static class Program
{
static void Main()
{
XElement ops = XElement.Load(@"c:\temp\exp.xml");
Tree<Element> domain = new Tree<Element>(
from cell in ops.Elements("cell")
select new TreeNode<Element>(
new Cell(
(string)cell.Attribute("name"),
(string)cell.Attribute("name"), null
),
from agent in cell.Elements("agent")
select new TreeNode<Element>(
new Agent(
(string)agent.Attribute("name"),
(string)agent.Attribute("name"), null
),
from na in agent.Elements("node-agent")
select new TreeNode<Element>(
new NodeAgent(
(string)na.Attribute("name"),
(string)na.Attribute("name"), null
)
)
)
)
);
}
}
其他提示
如果没有您的类和源代码xml,很难为您提供您所需的确切代码,但这就是我喜欢构建XML解析的方式:
XDocument d = XDocument.Parse(@"<a id=""7""><b><c name=""foo""/><c name=""bar""/></b><b/><b2/></a>");
var ae = d.Root;
var a = new A
{
Id = (int)ae.Attribute("id"),
Children = new List<B>(ae.Elements("b").Select(be => new B
{
Children = new List<C>(be.Elements("c").Select(ce => new C
{
Name = (string)ce.Attribute("name")
}))
}))
};
给出xml:
<a>
<b>
<c name="foo"/>
<c name="bar"/>
</b>
<b/>
<b2/>
</a>
和班级:
class A
{
public int Id { get; set; }
public List<B> Children { get; set; }
}
class B
{
public List<C> Children { get; set; }
}
class C
{
public string Name { get; set; }
}
不隶属于 StackOverflow