1

我正在进行一项练习,我试图从用户输入表的数据中手动创建一个 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 级深的对象树?

4

2 回答 2

1

希望这有帮助:

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

}
于 2012-11-09T12:29:41.857 回答
0

首先想到的是处理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 + "  ");
}
于 2012-11-09T12:16:53.553 回答