Linq to XML을 사용하여 심층 개체 그래프를 만들고 리팩토링하시겠습니까?
-
06-07-2019 - |
문제
LINQ to XML을 사용하여 간단한 XML 파일 파서를 작성 중입니다.
XML의 각 요소에 대해 TreeNode 개체(예: 간단한 트리 구조)를 갖고 싶습니다.각 요소에 강력한 형식을 지정하고 싶습니다.
이전에 사용했던 단순한 반복 접근 방식(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
등), 우리는 별도의 "TreeNode<T>
" 모델을 사용하여 항목을 트리 내부에 배치합니다(항목을 관련 컬렉션으로 모델링하기 위해 항목을 변경하는 대신).나는 또한 우리가 더 많은 자유를 누릴 수 있다고 가정했습니다. TreeNode<T>
엔터티를 사용하는 것보다 더 많은 것을 허용하는 생성자를 도입했습니다. 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