如何解决如何在.NET中反序列化为本地集合?
我正在尝试在.NET中建立数据管道。给我一个xsd
,并用XML Schema Definition Tool生成了代表对象模型的C#类。为了将这些数据加载到我的数据存储中,我需要将来自XML的数据转换为与我的应用程序模式和collection / dedupe元素匹配的结构。为此,我有一个解析器类,该类将读取文件并将内容加载到本地集合中,然后将其加载到我的数据库中。我看到两个选项可以做到这一点-
- 使用
XmlReader
手动遍历XML,并提取所需的数据,并将其加载到流中的本地集合中。这是不理想的,因为它没有利用我给定的强类型/严格xsd
的优势,并且需要大量的硬编码,例如while (reader.Read())
,检查特定的XML节点,然后使用“阅读器” .GetAttribute(“ HardCodedString”)。 - 使用
XmlSerializer
立即对整个文件进行反序列化,然后循环遍历反序列化的集合并插入到我的本地集合中。这是不理想的,因为文件可能很大,并且此方法迫使我循环遍历所有数据两次(一次进行反序列化,一次将数据提取到本地集合中)。
理想情况下,我想以某种方式注册要执行的委托,因为每个对象都被反序列化以插入到我的本地集合中。框架中是否可以执行此操作?要求如下:
我创建了一个最小的例子来说明我的观点。
示例XML文件:
<Hierarchy xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.example.com/example">
<Children>
<Child ChildId="1" ChildName="First">
<Parents>
<Parent ParentId="1" ParentName="First" RelationshipStart="1900-01-01T00:00:00"/>
<Parent ParentId="2" ParentName="Second" RelationshipStart="2000-01-01T00:00:00"/>
</Parents>
</Child>
<Child ChildId="2" ChildName="Second">
<Parents>
<Parent ParentId="2" ParentName="Second" RelationshipStart="1900-01-01T00:00:00"/>
<Parent ParentId="3" ParentName="Third" RelationshipStart="2000-01-01T00:00:00"/>
</Parents>
</Child>
</Children>
</Hierarchy>
我要加载的本地收藏集:
public Dictionary<int,string> Parents { get; }
public Dictionary<int,string> Children { get; }
public List<Relationship> Relationships { get; }
手动版本(不可维护,不使用xsd
):
public void ParseFileManually(string fileName)
{
using (var reader = XmlReader.Create(fileName))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Hierarchy")
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Child")
{
int childId = int.Parse(reader.GetAttribute("ChildId"));
string childName = reader.GetAttribute("ChildName");
Children[childId] = childName;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Parent")
{
int parentId = int.Parse(reader.GetAttribute("ParentId"));
string parentName = reader.GetAttribute("ParentName");
DateTime relationshipStart = DateTime.Parse(reader.GetAttribute("RelationshipStart"));
Parents[parentId] = parentName;
Relationships.Add(
new Relationship{
ParentId = parentId,ChildId = childId,Start = relationshipStart
});
}
else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Child")
{
break;
}
}
}
}
}
}
}
}
反序列化版本(两次遍历数据):
public void ParseFileWithDeserialize(string fileName)
{
var serializer = new XmlSerializer(typeof(Hierarchy));
using (var fileStream = new FileStream(fileName,FileMode.Open))
{
var fileData = (Hierarchy) serializer.Deserialize(fileStream);
foreach (var child in fileData.Children)
{
Children[child.ChildId] = child.ChildName;
foreach (var parent in child.Parents)
{
Parents[parent.ParentId] = parent.ParentName;
Relationships.Add(
new Relationship
{
ParentId = parent.ParentId,ChildId = child.ChildId,Start = parent.RelationshipStart
});
}
}
}
}
解决方法
如果使用这些定义,则应使用一些批注从XML的正确字段中获取数据;
public class Hierarchy
{
public Hierarchy()
{
Children = new List<Child>();
}
public List<Child> Children { get; set; }
}
public class Child
{
public Child()
{
Parents = new List<Parent>();
}
[XmlAttribute("ChildId")]
public int ChildId { get; set; }
[XmlAttribute("ChildName")]
public string ChildName { get; set; }
public List<Parent> Parents { get; set; }
}
public class Parent
{
[XmlAttribute("ParentId")]
public int ParentId { get; set; }
[XmlAttribute("ParentName")]
public string ParentName { get; set; }
[XmlAttribute("RelationshipStart")]
public DateTime RelationshipStart { get; set; }
}
然后,您应该可以将代码简化为;
public static Hierarchy Deserialize(string fileName)
{
using (var fileStream = new StreamReader(fileName,Encoding.UTF8))
{
XmlSerializer ser = new XmlSerializer(typeof(Hierarchy));
return (Hierarchy)ser.Deserialize(fileStream);
}
}
要对其进行测试,您可以创建一个示例数据集并将其序列化为文件,然后使用上面的代码将其读回
public static void Serialize(Hierarchy h,string fileName)
{
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(Hierarchy));
StreamWriter sw = new StreamWriter(fileName,false,Encoding.UTF8);
ser.Serialize(sw,h);
}
测试代码
static void Test()
{
Hierarchy h = new Hierarchy();
Parent p1 = new Parent() { ParentId = 1,ParentName = "First",RelationshipStart = DateTime.Now };
Parent p2 = new Parent() { ParentId = 2,ParentName = "Second",RelationshipStart = DateTime.Now };
Parent p3 = new Parent() { ParentId = 3,ParentName = "Third",RelationshipStart = DateTime.Now };
Child c1 = new Child() { ChildId = 1,ChildName = "First" };
c1.Parents.Add(p1);
c1.Parents.Add(p2);
Child c2 = new Child() { ChildId = 2,ChildName = "Second" };
c2.Parents.Add(p2);
c2.Parents.Add(p3);
h.Children.Add(c1);
h.Children.Add(c2);
Serialize(h,AppContext.BaseDirectory + "Text.xml");
Hierarchy hReadBack = Deserialize(AppContext.BaseDirectory + "Text.xml");
}
编辑:回答您的问题
使用这些类
public class Hierarchy
{
public Hierarchy()
{
Children = new List<Child>();
}
public List<Child> Children { get; set; }
private Dictionary<int,string> _parents;
private Dictionary<int,string> _childrenList;
private List<Relationship> _relationships;
private void CalcuateLists()
{
_parents = new Dictionary<int,string>();
_childrenList = new Dictionary<int,string>();
_relationships = new List<Relationship>();
foreach (Child c in this.Children)
{
if (!_childrenList.ContainsKey(c.ChildId))
{
_childrenList.Add(c.ChildId,c.ChildName);
}
foreach (Parent p in c.Parents)
{
if (!_parents.ContainsKey(p.ParentId))
{
_parents.Add(p.ParentId,p.ParentName);
}
if (_relationships.FirstOrDefault(dat => dat.ParentId == p.ParentId && dat.ChildId == c.ChildId) == null)
{
_relationships.Add(new Relationship() { ChildId = c.ChildId,ParentId = p.ParentId,Start = p.RelationshipStart });
}
}
}
}
public Dictionary<int,string> Parents {
get
{
if (_parents == null)
CalcuateLists();
return _parents;
}
}
public Dictionary<int,string> ChildrenList {
get
{
if (_childrenList == null)
CalcuateLists();
return _childrenList;
}
}
public List<Relationship> Relationships {
get
{
if (_relationships == null)
CalcuateLists();
return _relationships;
}
}
}
public class Child
{
public Child()
{
Parents = new List<Parent>();
}
[XmlAttribute("ChildId")]
public int ChildId { get; set; }
[XmlAttribute("ChildName")]
public string ChildName { get; set; }
public List<Parent> Parents { get; set; }
}
public class Parent
{
[XmlAttribute("ParentId")]
public int ParentId { get; set; }
[XmlAttribute("ParentName")]
public string ParentName { get; set; }
[XmlAttribute("RelationshipStart")]
public DateTime RelationshipStart { get; set; }
}
然后您的测试代码变为
public static void Test()
{
Hierarchy h = new Hierarchy();
Parent p1 = new Parent() { ParentId = 1,RelationshipStart = DateTime.Now };
Parent p2 = new Parent() { ParentId = 2,RelationshipStart = DateTime.Now };
Parent p3 = new Parent() { ParentId = 3,RelationshipStart = DateTime.Now };
Child c1 = new Child() { ChildId = 1,ChildName = "First" };
c1.Parents.Add(p1);
c1.Parents.Add(p2);
Child c2 = new Child() { ChildId = 2,ChildName = "Second" };
c2.Parents.Add(p2);
c2.Parents.Add(p3);
h.Children.Add(c1);
h.Children.Add(c2);
Serialize(h,AppContext.BaseDirectory + "Text.xml");
Hierarchy hReadBack = Deserialize(AppContext.BaseDirectory + "Text.xml");
Dictionary<int,string> Parents = hReadBack.Parents;
Dictionary<int,string> Children = hReadBack.ChildrenList;
List<Relationship> Relationships = hReadBack.Relationships;
}
编辑
直接获得结果而无需循环
您将需要此类
public class Relationship
{
public int ParentId { get; set; }
public int ChildId { get; set; }
public DateTime Start { get; set; }
}
这个选择
// Get a list of child ids and names
Dictionary<int,string> Children = (from c in hReadBack.Children select new { ChildId = c.ChildId,Name = c.ChildName}).ToDictionary(dat => dat.ChildId,dat => dat.Name);
// Get a parent ids and names
Dictionary<int,string> Parents = (from p in hReadBack.Children.SelectMany(i => i.Parents) select new { ParentId = p.ParentId,Name = p.ParentName }).Distinct().ToDictionary(dat => dat.ParentId,dat => dat.Name);
// Get the relationships
List<Relationship> Relationship = (from Child c in hReadBack.Children from Parent p in c.Parents select new Relationship() { ChildId = c.ChildId,Start = p.RelationshipStart }).ToList();
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。