如何将大型 xml 文件的一部分反序列化为 c# 类
本文关键字:反序列化 一部分 文件 大型 xml | 更新日期: 2023-09-27 17:56:22
我已经阅读了一些关于如何反序列化xml的文章和文章,但仍然没有弄清楚我应该如何编写代码以满足我的需求,所以..对于另一个关于反序列化 xml 的问题,我深表歉意))
我有一个大的(50 MB)xml文件,我需要反序列化。我使用 xsd.exe 来获取文档的 xsd 架构,而不是自动生成我放入项目中的 c# 类文件。我想从这个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();
我收到无效操作异常: 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
}
无效操作异常: 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.
那么,如何修复(或覆盖)代码以不出现异常呢?
编辑:同样当我写的时候:
XDocument doc = XDocument.Parse(@"C:'div_kid.xml");
出现 XmlException :根级别、字符串 1、位置 1 上不允许的数据。
下面是 xml 文件的第一个字符串:
<?xml version="1.0" encoding="windows-1251"?>
编辑 2:xml 文件简短示例:
<?xml version="1.0" encoding="windows-1251"?>
<!DOCTYPE yml_catalog SYSTEM "shops.dtd">
<yml_catalog date="2012-11-01 23:29">
<shop>
<name>OZON.ru</name>
<company>?????? "???????????????? ??????????????"</company>
<url>http://www.ozon.ru/</url>
<currencies>
<currency id="RUR" rate="1" />
</currencies>
<categories>
<category id=""1126233>base category</category>
<category id="1127479" parentId="1126233">bla bla bla</category>
// here goes all the categories
</categories>
<offers>
<offer>
<price></price>
<picture></picture>
</offer>
// other offers
</offers>
</shop>
</yml_catalog>
附言我已经接受了答案(这是完美的)。但是现在我需要使用 categoryId 为每个报价找到"基本类别"。数据是分层的,基本类别是没有"parentId"属性的类别。因此,我编写了一个递归方法来查找"基本类别",但它从未完成。似乎算法不是很快))
这是我的代码:(在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 表达式从文档中选择节点。然后创建包含您感兴趣的数据的匿名对象(或使用现有类)。
最好是看到它的实际效果。
- LINQ to XML 的其他示例
- 使用 xQuery 和 Lambda 的简单示例
- 表示命名空间的示例
- 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 Category
{
public int Id { get; set; }
public int? ParentId { get; set; }
public List<Category> Children { get; set; }
public IEnumerable<Category> 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<Category>()
}).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();