如何只将大型xml文件的一部分反序列化为c#类?

我已经阅读了一些关于如何反序列化xml的post和文章,但仍然没有想出我应该编写代码以满足我的需求的方式,所以..我为另一个关于反序列化xml的问题道歉))

我有一个大的(50 MB)xml文件,我需要反序列化。 我使用xsd.exe来获取文档的xsd模式,而不是自动生成我放入项目的c#classes文件。 我想从这个xml文件中获取一些(不是全部)数据并将其放入我的sql数据库中。

这是文件的层次结构(简化,xsd非常大):

public class yml_catalog { public yml_catalogShop[] shop { /*realization*/ } } public class yml_catalogShop { public yml_catalogShopOffersOffer[][] offers { /*realization*/ } } public class yml_catalogShopOffersOffer { // here goes all the data (properties) I want to obtain )) } 

这是我的代码:

第一种方法:

 yml_catalogShopOffersOffer catalog; var serializer = new XmlSerializer(typeof(yml_catalogShopOffersOffer)); var reader = new StreamReader(@"C:\div_kid.xml"); catalog = (yml_catalogShopOffersOffer) serializer.Deserialize(reader);//exception occures reader.Close(); 

我得到InvalidOperationException:XML(3,2)文档中有一个错误

第二种方法:

 XmlSerializer ser = new XmlSerializer(typeof(yml_catalogShopOffersOffer)); yml_catalogShopOffersOffer result; using (XmlReader reader = XmlReader.Create(@"C:\div_kid.xml")) { result = (yml_catalogShopOffersOffer)ser.Deserialize(reader); // exception occures } 

InvalidOperationException:XML(0,0)文档中存在错误

第三:我试图反序列化整个文件:

  XmlSerializer ser = new XmlSerializer(typeof(yml_catalog)); // exception occures yml_catalog result; using (XmlReader reader = XmlReader.Create(@"C:\div_kid.xml")) { result = (yml_catalog)ser.Deserialize(reader); } 

我得到以下内容:

 error CS0030: The convertion of type "yml_catalogShopOffersOffer[]" into "yml_catalogShopOffersOffer" is not possible. error CS0029: The implicit convertion of type "yml_catalogShopOffersOffer" into "yml_catalogShopOffersOffer[]" is not possible. 

那么,如何修复(或覆盖)代码以避免exception?

编辑:当我写:

 XDocument doc = XDocument.Parse(@"C:\div_kid.xml"); 

发生XmlException:根级别的未经许可的数据,字符串1,位置1。

这是xml文件的第一个字符串:

  

编辑2: xml文件简短示例:

     OZON.ru ?????? "???????????????? ??????????????" http://www.ozon.ru/     base category bla bla bla // here goes all the categories       // other offers    

PS我已经接受了答案(这是完美的)。 但现在我需要使用categoryId为每个Offer找到“基类别”。 数据是分层的,基类别是没有“parentId”属性的类别。 所以,我写了一个递归方法来找到“基类”,但它永远不会完成。 好像algorythm不是很快))
这是我的代码:(在main()方法中)

 var doc = XDocument.Load(@"C:\div_kid.xml"); var offers = doc.Descendants("shop").Elements("offers").Elements("offer"); foreach (var offer in offers.Take(2)) { var category = GetCategory(categoryId, doc); // here goes other code } 

助手方法:

 public static string GetCategory(int categoryId, XDocument document) { var tempId = categoryId; var categories = document.Descendants("shop").Elements("categories").Elements("category"); foreach (var category in categories) { if (category.Attribute("id").ToString() == categoryId.ToString()) { if (category.Attributes().Count() == 1) { return category.ToString(); } tempId = Convert.ToInt32(category.Attribute("parentId")); } } return GetCategory(tempId, document); } 

在这种情况下我可以使用递归吗? 如果没有,我怎么能找到“基类”?

尝试LINQ to XML。 XElement result = XElement.Load(@"C:\div_kid.xml");

在LINQ中查询是很棒的,但一开始肯定有点奇怪。 您可以使用SQL语法或使用lambda表达式从Document中选择节点。 然后创建包含您感兴趣的数据的匿名对象(或使用现有的类)。

最好是看到它在行动。

  • LINQ to XML的各种示例
  • 使用xquery和lambdas的简单示例
  • 表示命名空间的样本
  • 在msdn上还有更多。 搜索LINQ to XML。

根据您的示例XML和代码,这是一个具体示例:

 var element = XElement.Load(@"C:\div_kid.xml"); var shopsQuery = from shop in element.Descendants("shop") select new { Name = (string) shop.Descendants("name").FirstOrDefault(), Company = (string) shop.Descendants("company").FirstOrDefault(), Categories = from category in shop.Descendants("category") select new { Id = category.Attribute("id").Value, Parent = category.Attribute("parentId").Value, Name = category.Value }, Offers = from offer in shop.Descendants("offer") select new { Price = (string) offer.Descendants("price").FirstOrDefault(), Picture = (string) offer.Descendants("picture").FirstOrDefault() } }; foreach (var shop in shopsQuery){ Console.WriteLine(shop.Name); Console.WriteLine(shop.Company); foreach (var category in shop.Categories) { Console.WriteLine(category.Name); Console.WriteLine(category.Id); } foreach (var offer in shop.Offers) { Console.WriteLine(offer.Price); Console.WriteLine(offer.Picture); } } 

作为额外:以下是如何从平面category元素反序列化类别树。 你需要一个合适的class级来容纳他们,因为孩子的名单必须有一个类型:

 class Category { public int Id { get; set; } public int? ParentId { get; set; } public List Children { get; set; } public IEnumerable Descendants { get { return (from child in Children select child.Descendants).SelectMany(x => x). Concat(new Category[] { this }); } } } 

要创建包含文档中所有不同类别的列表:

 var categories = (from category in element.Descendants("category") orderby int.Parse( category.Attribute("id").Value ) select new Category() { Id = int.Parse(category.Attribute("id").Value), ParentId = category.Attribute("parentId") == null ? null as int? : int.Parse(category.Attribute("parentId").Value), Children = new List() }).Distinct().ToList(); 

然后将它们组织成一棵树(从平面列表借用层次结构到层次结构 ):

 var lookup = categories.ToLookup(cat => cat.ParentId); foreach (var category in categories) { category.Children = lookup[category.Id].ToList(); } var rootCategories = lookup[null].ToList(); 

要查找包含该theCategory的根:

 var root = (from cat in rootCategories where cat.Descendants.Contains(theCategory) select cat).FirstOrDefault();