如何使用数据表在C#中构建数据层次结构



我正处于练习的中间,我试图从用户进入表中的数据中手动制作XML文件。这是一个示例表:

注意,在我的代码示例中,出于将来的目的,该表揭示了更多的字段。

注2,该表中的数据由用户手动输入到我的Windows表单应用程序上的DataGridView控件中。这里不涉及SQL。

ID | ParentID | Element | DefaultValue |
========================================
0  | -1       | root    |              |
1  | 0        | first   | SomeData     |
2  | 0        | second  | OtherData    |
3  | 0        | third   |              |
4  | 3        | firstCh | Child of ID=3| 
========================================

我试图使用C#从此构建XML文件,而无需使用任何XML类。我试图通过纯粹的字符串操纵和格式来做到这一点,因为如果此测试成功,我可能会将其扩展以做更多的事情,这些事情可以证明在我们工作的生产环境中对我们有用。

我当前的思维模式是通过每个元素迭代,确定某个ID的元素是否包含一个孩子,在这些孩子中构建对象列表。通过儿童名单进行迭代,然后确定儿童名单中的儿童元素中是否存在"孙子"。这是我完成的代码类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XMLtoXSDconverter
{
    class XMLConstruct
    {
        public enum ElementType { None, StringElement, LongElement, BoolElement, DateTimeElement, FloatElement, IntElement, DoubleElement };
        public int id;
        public int parentID;
        public string element;
        public string comment;
        public int minOccurs;
        public int maxOccurs;
        List<XMLConstruct> children;
        int indent = 0;
        public string buildXMLConstruct(int id, int parentId, string element, string comment, ElementType elementType, List<XMLConstruct> children, int minOccurs, int maxOccurs)
        {
            this.id = id;
            this.parentID = parentId;
            this.element = element;
            this.comment = comment;
            this.minOccurs = minOccurs;
            this.maxOccurs = maxOccurs;
            string elementTypeString = string.Empty;
            switch (elementType)
            {
                case ElementType.StringElement: elementTypeString = "xs:string"; break;
                case ElementType.LongElement: elementTypeString = "xs:long"; break;
                case ElementType.IntElement: elementTypeString = "xs:int"; break;
                case ElementType.FloatElement: elementTypeString = "xs:float"; break;
                case ElementType.DoubleElement: elementTypeString = "xs:double"; break;
                case ElementType.DateTimeElement: elementTypeString = "xs:dateTime"; break;
                case ElementType.BoolElement: elementTypeString = "xs:boolean"; break;
                default: elementTypeString = string.Empty; break;
            }
            if (this.id == 0)
                element += "Wrapper";
            //Hiccup here, how would I construct the children elements? Recursion perhaps? These children should come in the List<XSDConstruct>, which may contain children too
            return null;
        }
    }
}

我一直在嘲笑如何解决这个问题以及如何解决问题。如您所见,读者和我在这个星期五下午的噩梦中可能的救星,XSDConstruct包含能够制作XML和XSD文件所需的大多数字段。有一个List<XSDConstruct>子对象可以包含每个元素的子女,依此类推,显然在使用递归时大喊大叫。

所以我的问题是,我如何将表中的数据读取到对象中,以包含一个对象树,n-级别深度?

希望此帮助:

Node MakeTree()
{   
    // create root, build subtree and return it
    var node = new Node() {Id = 0, ParentId = -1};
    MakeSubTree(node);
    return node;
}
void MakeSubTree(Node parentNode)
{
    // find all children of parent node (they have parentId = id of parent node)
    var nodes = TableItems.Where(e => e.ParentId == parentNode.Id)
                    .Select(e => new Node {ParentId = e.ParentId, Id = e.Id});
    // build subtree for each child and add it in parent's children collection
    foreach (var node in nodes)
    {
        MakeSubTree(node);
        parentNode.Children.Add(node);             
    }
}

TableItems是您的物品的收集。Node类定义为:

public class Node
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public List<Node> Children { get; set; } 
    public Node()
    {
        Children = new List<Node>();
    }
}

首先想到的是处理XMLConstruct构造师之外的孩子。您应该能够构建这样的查找表:

var lookupTable = new Dictionary<int, XMLConstruct>();
// note: this is probably not how you iterate over gridview rows,
// just making a proof of concept:
foreach(var row in gridView)
{
    var xc = GetXmlConstruct(row); // build the construct from the gridvew row
    lookupTable.Add(xc.id, xc);
}

现在您拥有所有构造,您可以通过所有结构进行通过并分配孩子:

foreach(var xc in lookupTable.Values)
{
    XMLConstruct parent;
    if (lookupTable.TryGetValue(xc.parentID, out parent))
        parent.children.Add(xc);
}

必须初始化children属性,否则您将获得无效指针例外。

现在可以像这样穿过树:

// assuming that the element with id=0 is the root element
var rootElement = lookupTable[0];
Traverse(rootElement, "");
// remember, this is just a proof of concept, 
// you probably need to render opening/ending tags etc.
public Traverse(XMLConstruct xc, string indentation)
{
    Console.WriteLine(indentation + xc.Element);
    foreach(var child in xc.Children)
        Traverse(child, indentation + "  ");
}

最新更新