C# XML树生成

C# XML树生成,c#,xml,C#,Xml,我有一个“平面”XML菜单,需要对其进行结构化 当前XML树: <root> <nodes> <node> <id>5</id> <parent>1</parent> </node> <node> <id>8</id>

我有一个“平面”XML菜单,需要对其进行结构化

当前XML树:

<root>
    <nodes>
        <node>
            <id>5</id>
            <parent>1</parent>
        </node>
        <node>
            <id>8</id>
            <parent>5</parent>
        </node>
        <node>
            <id>14</id>
            <parent>8</parent>
        </node>
        <node>
            <id>26</id>
            <parent>1</parent>
        </node>
    </nodes>    
</root>
正如您所看到的,我的节点还包含“type”和“name”。类型用于确定节点是“文件夹”还是“产品”

我的问题是,它没有返回正确的XML。如果我删除上一节中的nodes.RemoveChild(n),那么效果很好,但是我不想删除我知道没有任何子项的子项(products,type=1)


如果此代码正在运行。我只得到几个节点。

我将采用不同的方法来解决这个问题。您现在正试图通过移动节点来修改现有文档,这相当复杂。我将解析原始文档,将其存储在某个数据结构中,然后再次将其写入另一个位置

您的数据结构如下所示:

public class Node
{
    public SomeClass NodeData { get ; set; }
    public List<Node> Children { get; }
}
Node rootNode = ParseXml(...);
WriteStructuredXml(rootNode);

这两种方法都不难编写。通过这种方式,您可以将问题分为两个更小、更简单的问题。

此代码完成此任务。希望足够清楚

public class Node
{
    public Node()
    {
        Children = new List<Node>();
    }

    public int Id;

    public int ParentId;

    public List<Node> Children;

    public Node Parent;

    public static Node Deserialize(XmlElement xNode)
    {
        Node n = new Node();
        XmlElement xId = xNode.SelectSingleNode("id") as XmlElement;
        n.Id = int.Parse(xId.InnerText);
        XmlElement xParent = xNode.SelectSingleNode("parent") as XmlElement;
        n.ParentId = int.Parse(xParent.InnerText);
        return n;
    }

    public void AddChild(Node child)
    {
        Children.Add(child);
        child.Parent = this;
    }

    public void Serialize(XmlElement xParent)
    {
        XmlElement xNode = xParent.OwnerDocument.CreateElement("node");
        XmlElement xId = xParent.OwnerDocument.CreateElement("id");
        xId.InnerText = Id.ToString();
        xNode.AppendChild(xId);
        XmlElement xParentId = xParent.OwnerDocument.CreateElement("parent");
        xParentId.InnerText = ParentId.ToString();
        xNode.AppendChild(xParentId);
        foreach (Node child in Children)
            child.Serialize(xNode);
        xParent.AppendChild(xNode);
    }
}

public static XmlDocument DeserializeAndReserialize(XmlDocument flatDoc)
{
    Dictionary<int, Node> nodes = new Dictionary<int, Node>();
    foreach (XmlElement x in flatDoc.SelectNodes("//node"))
    {
        Node n = Node.Deserialize(x);
        nodes[n.Id] = n;
    }

    // at the end, retrieve parents for each node
    foreach (Node n in nodes.Values)
    {
        Node parent;
        if (nodes.TryGetValue(n.ParentId, out parent))
        {
           parent.AddChild(n);
        }
    }

    XmlDocument orderedDoc = new XmlDocument();
    XmlElement root = orderedDoc.CreateElement("root");
    orderedDoc.AppendChild(root);
    XmlElement xnodes = orderedDoc.CreateElement("nodes");
    foreach (Node n in nodes.Values)
    {
        if (n.Parent == null)
            n.Serialize(xnodes);
    }
    root.AppendChild(xnodes);
    return orderedDoc;
}
公共类节点
{
公共节点()
{
Children=新列表();
}
公共int Id;
公共int-ParentId;
公开儿童名单;
公共节点父节点;
公共静态节点反序列化(XmlElement xNode)
{
节点n=新节点();
XmlElement xId=xNode。选择SingleNode(“id”)作为XmlElement;
n、 Id=int.Parse(xId.InnerText);
XmlElement xParent=xNode。选择SingleNode(“父节点”)作为XmlElement;
n、 ParentId=int.Parse(xParent.InnerText);
返回n;
}
公共void AddChild(节点子节点)
{
添加(child);
child.Parent=this;
}
公共void序列化(XmlElement xParent)
{
XmlElement xNode=xParent.OwnerDocument.CreateElement(“节点”);
XmlElement xId=xParent.OwnerDocument.CreateElement(“id”);
xId.InnerText=Id.ToString();
xNode.AppendChild(xId);
xmlementxparentid=xParent.OwnerDocument.CreateElement(“父”);
xParentId.InnerText=ParentId.ToString();
AppendChild(xParentId);
foreach(子节点中的节点子节点)
序列化(xNode);
xParent.AppendChild(xNode);
}
}
公共静态XmlDocument反序列化和序列化(XmlDocument flatDoc)
{
字典节点=新字典();
foreach(flatDoc.SelectNodes(“//节点”)中的XmlElement x)
{
Node n=Node.反序列化(x);
节点[n.Id]=n;
}
//最后,检索每个节点的父节点
foreach(nodes.Values中的节点n)
{
节点父节点;
if(nodes.TryGetValue(n.ParentId,out parent))
{
parent.AddChild(n);
}
}
XmlDocument orderedDoc=新的XmlDocument();
xmlementroot=orderedoc.CreateElement(“根”);
orderedDoc.AppendChild(根);
XmlElement xnodes=orderedDoc.CreateElement(“节点”);
foreach(nodes.Values中的节点n)
{
如果(n.Parent==null)
n、 序列化(xnodes);
}
AppendChild(xnodes);
退货订单DOC;
}

以下是一些代码,用于获取所有名为“node”的节点:

    public static IEnumerable<XmlNode> GetNodes(XmlDocument xdoc)
    {
        var nodes = new List<XmlNode>();

        Queue<XmlNode> toProcess = new Queue<XmlNode>();

        if (xdoc != null)
        {
            foreach (var node in GetChildElements(xdoc))
            {
                toProcess.Enqueue(node);
            }
        }

        do
        {
            //get a node to process
            var node = toProcess.Dequeue();

            // add node to found list if name matches
            if (node.Name == "node")
            {
                nodes.Add(node);
            }

            // get the node's children
            var children = GetChildElements(node);

            // add children to queue.
            foreach (var n in children)
            {
                toProcess.Enqueue(n);
            }

            // continue while queue contains items.
        } while (toProcess.Count > 0);


        return nodes;
    }

    private static IEnumerable<XmlNode> GetChildElements(XmlNode node)
    {
        if (node == null || node.ChildNodes == null) return new List<XmlNode>();

        return node.ChildNodes.Cast<XmlNode>().Where(n=>n.NodeType == XmlNodeType.Element);
    }
公共静态IEnumerable GetNodes(XmlDocument xdoc)
{
var节点=新列表();
Queue toProcess=新队列();
如果(xdoc!=null)
{
foreach(GetChildElements(xdoc)中的var节点)
{
toProcess.Enqueue(节点);
}
}
做
{
//获取要处理的节点
var node=toProcess.Dequeue();
//如果名称匹配,则将节点添加到找到的列表中
如果(node.Name==“node”)
{
nodes.Add(node);
}
//获取节点的子节点
var children=GetChildElements(节点);
//将子项添加到队列。
foreach(儿童中的n变量)
{
toProcess.Enqueue(n);
}
//当队列包含项目时继续。
}而(toProcess.Count>0);
返回节点;
}
私有静态IEnumerable GetChildElements(XmlNode)
{
如果(node==null | | node.ChildNodes==null)返回新列表();
返回node.ChildNodes.Cast(),其中(n=>n.NodeType==XmlNodeType.Element);
}

然后需要根据父子关系移动节点。看看@PierrOz的答案。

就是这样!谢谢你,很高兴看到专业人士如何处理这件事!我想快速使用我熟记的代码。如果有更多的时间,我会尝试使用System.Xml.Linq。使用这个程序集操作Xml要容易得多。你是对的,应该按照你建议的方式处理。谢谢你的建议!
public class Node
{
    public Node()
    {
        Children = new List<Node>();
    }

    public int Id;

    public int ParentId;

    public List<Node> Children;

    public Node Parent;

    public static Node Deserialize(XmlElement xNode)
    {
        Node n = new Node();
        XmlElement xId = xNode.SelectSingleNode("id") as XmlElement;
        n.Id = int.Parse(xId.InnerText);
        XmlElement xParent = xNode.SelectSingleNode("parent") as XmlElement;
        n.ParentId = int.Parse(xParent.InnerText);
        return n;
    }

    public void AddChild(Node child)
    {
        Children.Add(child);
        child.Parent = this;
    }

    public void Serialize(XmlElement xParent)
    {
        XmlElement xNode = xParent.OwnerDocument.CreateElement("node");
        XmlElement xId = xParent.OwnerDocument.CreateElement("id");
        xId.InnerText = Id.ToString();
        xNode.AppendChild(xId);
        XmlElement xParentId = xParent.OwnerDocument.CreateElement("parent");
        xParentId.InnerText = ParentId.ToString();
        xNode.AppendChild(xParentId);
        foreach (Node child in Children)
            child.Serialize(xNode);
        xParent.AppendChild(xNode);
    }
}

public static XmlDocument DeserializeAndReserialize(XmlDocument flatDoc)
{
    Dictionary<int, Node> nodes = new Dictionary<int, Node>();
    foreach (XmlElement x in flatDoc.SelectNodes("//node"))
    {
        Node n = Node.Deserialize(x);
        nodes[n.Id] = n;
    }

    // at the end, retrieve parents for each node
    foreach (Node n in nodes.Values)
    {
        Node parent;
        if (nodes.TryGetValue(n.ParentId, out parent))
        {
           parent.AddChild(n);
        }
    }

    XmlDocument orderedDoc = new XmlDocument();
    XmlElement root = orderedDoc.CreateElement("root");
    orderedDoc.AppendChild(root);
    XmlElement xnodes = orderedDoc.CreateElement("nodes");
    foreach (Node n in nodes.Values)
    {
        if (n.Parent == null)
            n.Serialize(xnodes);
    }
    root.AppendChild(xnodes);
    return orderedDoc;
}
    public static IEnumerable<XmlNode> GetNodes(XmlDocument xdoc)
    {
        var nodes = new List<XmlNode>();

        Queue<XmlNode> toProcess = new Queue<XmlNode>();

        if (xdoc != null)
        {
            foreach (var node in GetChildElements(xdoc))
            {
                toProcess.Enqueue(node);
            }
        }

        do
        {
            //get a node to process
            var node = toProcess.Dequeue();

            // add node to found list if name matches
            if (node.Name == "node")
            {
                nodes.Add(node);
            }

            // get the node's children
            var children = GetChildElements(node);

            // add children to queue.
            foreach (var n in children)
            {
                toProcess.Enqueue(n);
            }

            // continue while queue contains items.
        } while (toProcess.Count > 0);


        return nodes;
    }

    private static IEnumerable<XmlNode> GetChildElements(XmlNode node)
    {
        if (node == null || node.ChildNodes == null) return new List<XmlNode>();

        return node.ChildNodes.Cast<XmlNode>().Where(n=>n.NodeType == XmlNodeType.Element);
    }