Linq to XML을 사용하여 심층 개체 그래프를 만들고 리팩토링하시겠습니까?

StackOverflow https://stackoverflow.com/questions/1613569

  •  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; }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top