Frage

Ich schreibe einen einfachen XML-Datei-Parser LINQ to XML.

Ich möchte ein TreeNode-Objekt haben (das heißt eine einfache Baumstruktur) für jedes Element in der XML. Ich möchte jedes Element stark typisiert werden.

Es sieht hässlich und redundanten im Vergleich zu dem einfachen Looping Ansatz, den ich vor wurde mit (mit System.XML). Gibt es eine Möglichkeit hier die Redundanzen Streifen aus?

        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);
                }
            }
        }
War es hilfreich?

Lösung

Es ist schwer, diese vollständig ohne Beispieldaten und tatsächlichen Typen zu beantworten, aber ich würde es wie unter Refactoring.

Aus dem ursprünglichen Beispiel, ich nehme an, dass wir mit den Konstrukteuren der Einheiten zu verwirren wollen nicht (Agent etc), und dass wir die separate „TreeNode<T>“ Modell beibehalten möchten, setzen unsere Einheiten im Inneren des Baumes ( anstatt die Einheiten Dinge zu verändern, das damit verbundene Sammlungen zu modellieren). Ich habe auch davon ausgegangen, dass wir mehr Freiheiten mit TreeNode<T> nehmen können, als wir können mit den Entitäten, also habe ich einen Konstruktor eingeführt, die IEnumerable<...> akzeptiert, da dies mit LINQ Unterabfragen verwenden können:

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

Mit Framework-Code unten:

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

Andere Tipps

Ohne Ihre Klassen und Quelle xml, es ist ziemlich schwer, das Sie mit dem genauen Code liefern Sie nach, aber hier ist, wie Ich mag meine XML-Analyse strukturieren:

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

In Anbetracht der xml:

<a>
  <b>
    <c name="foo"/>
    <c name="bar"/>
  </b>
  <b/>
  <b2/>
</a>

und die Klassen:

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; }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top