我正处于练习的中间,我试图从用户进入表中的数据中手动制作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 + " ");
}