XML 如何解析为自定义类?
How can XML be parsed into custom classes?
我有包含 xml 的字符串,我需要循环遍历、解析和构建自定义 classes 的实例,以便插入到我的数据库中。
我需要的伪代码是这样的:
private List<SiteMapping> ExtractSiteMappingsFromXML(String xmlData)
{
List<SiteMapping> sitemaps = new List<SiteMapping>();
// parse xmlData, dynamically instantiating a SiteMapping class for each SiteMapping "record"
in the xml
foreach (record rec in xmlData)
{
SiteMapping sm = new SiteMapping();
sm.Id = //current id found in the xml data
sm.siteName = // current site name found in the xml data
. . .
sitemaps.Add(sm);
}
return sitemaps;
}
ExtractSiteMappingsFromXML() 的调用者将遍历返回的 SiteMapping 列表,并将记录插入数据库。
根据我从 here 那里得到的想法,我认为这样的事情是可能的:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlData);
XmlNodeList _ids = doc.GetElementsByTagName("Id");
XmlNodeList _sitenames = doc.GetElementsByTagName("siteName");
. . . // add an XmlNodeList for each element
然后我可以遍历 XmlNodeLists,例如:
for (int i = 0; i < _ids.Count; i++)
{
SiteMapping sm = new SiteMapping();
sm.Id =_ids[i];
sm.siteName = _sitenames[i];
. . . // add the rest
sitemaps.Add(sm);
}
这合理吗?如果一个或多个元素具有空白值,这仍然有效吗? IOW,如果一个元素有时是空白的,它会向相应的 XmlNodeList 添加一个空白值(这就是我想要的),还是什么都不添加,从而造成不匹配?
是否有一种优雅的 linqy (LINQ-to-XML) 方式来做到这一点?
注意:这是一个 Compact Framework 应用程序,因此在实施方面受到这些限制。
更新
我想也许这个代码:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(omnivore);
List<SiteQuery> sitequeries =
(from sitequery in xmlDoc.Descendants("SiteQuery")
select new SiteQuery
{
Id = sitequery.Element("Id").Value,
UPC_PackSize = sitequery.Element("UPC_PackSize").Value,
UPC_Code = sitequery.Element("UPC_Code").Value,
}).ToList<SiteQuery>();
...我从 here 改编而来,可以解决问题,但我得到,“方法 'Descendants' 没有重载需要 1 个参数 “
更新 2
我试过了(XDocument 而不是 XmlDocument):
XDocument xmlDoc = new XDocument();
XDocument.Parse(omnivore);
List<SiteQuery> sitequeries =
(from sitequery in xmlDoc.Descendants("SiteQuery")
select new SiteQuery
{
Id = Convert.ToInt32(sitequery.Element("Id").Value),
UPC_PackSize = Convert.ToInt32(sitequery.Element("UPC_PackSize").Value),
UPC_Code = sitequery.Element("UPC_Code").Value
}).ToList<SiteQuery>();
我不得不使用“XDocument.Parse(omnivore);”而不是“xmlDoc.Parse( omnivore);", 但编译器告诉我这是必要的...?!?
不足为奇,在此代码运行后站点查询的计数为 0,但是...
更新 3
也许 Nitin Aggarwal 的代码可以工作(它确实可以编译),但在运行时我得到:
System.InvalidOperationException was unhandled
_HResult=-2146233079
_message=There is an error in XML document (1, 2).
HResult=-2146233079
IsTransient=false
Message=There is an error in XML document (1, 2).
Source=System.Xml
StackTrace:
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader). . .
可能只是XML不好;而且,我不知道这些 jet-age classes 在 Compact Framework 中是否可用(我已经在 .NET 4.5.1 测试应用程序中编译)。
更新 4
Vishal,为了回答您的问题,这是我要解析的 XML:
<ArrayOfSiteQuery xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/CStore.DomainModels.HHS"><SiteQuery><Id>00006000002</Id><UPCPackSize>1</UPCPackSize><UPC_Code>00006000002</UPC_Code><crvId></crvId><dept>8</dept><description>ZZ</description><openQty>0.0</openQty><packSize>1</packSize><subDept>80</subDept><unitCost>1.25</unitCost><unitList>5.0</unitList><vendorId>CONFLICT</vendorId><vendorItem>123456</vendorItem></SiteQuery>
. . . (beaucoup other SiteQuery "records")
<SiteQuery><Id>5705654</Id><UPCPackSize>1</UPCPackSize><UPC_Code>5705654</UPC_Code><crvId></crvId><dept>2</dept><description>what do you want</description><openQty>0.0</openQty><packSize>1</packSize><subDept>0</subDept><unitCost>0.55</unitCost><unitList>1.62</unitList><vendorId></vendorId><vendorItem></vendorItem></SiteQuery></ArrayOfSiteQuery>
是否需要先去掉开头的位(<ArrayOfSiteQuery xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/CStore.DomainModels.HHS">
)和末尾的"close tag"()?
顺便说一句,"CStore.DomainModels.HHS" 在服务器应用程序中,客户端可能不知道那是什么。
更新 5
查看字符串中的xml,发现其内容与我自定义的class不符(是同一个数据,只是部分成员名称不同,彼此乱序),所以我更改了自定义 class 以匹配 xml:
public class SiteQuery
{
public int Id { get; set; }
public int UPCPackSize { get; set; }
public String UPC_Code { get; set; }
public String crvId { get; set; }
public int dept { get; set; }
public String description { get; set; }
public Double openQty { get; set; }
public int packSize { get; set; }
public int subDept { get; set; }
public Decimal unitCost { get; set; }
public Decimal unitList { get; set; }
public String vendorId { get; set; }
public String vendorItem { get; set; }
}
...但我仍然遇到相同的 InvalidOp 异常...
更新 6
甚至在我从 xml 中删除前导码和后导码后,它只包含 SiteQuery "xml records",将其保存为文件并加载它以进行处理:
String testData = File.ReadAllText("siteQueryTest.txt");
XmlSerializer serializer = new XmlSerializer(typeof(List<SiteQuery>));
XmlReader reader = XmlReader.Create(new StringReader(testData));
List<SiteQuery> siteQueries;
siteQueries = (List<SiteQuery>)serializer.Deserialize(reader);
...我仍然收到运行时错误:
System.InvalidOperationException was unhandled
_HResult=-2146233079
_message=There is an error in XML document (1, 2).
HResult=-2146233079
IsTransient=false
Message=There is an error in XML document (1, 2).
Source=System.Xml
StackTrace:
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader)
at Sandbox.Form1.button56_Click(Object sender, EventArgs e) in c:\HoldingTank\Sandbox\Form1.cs:line 2061
. . .
StackTrace:
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderList1.Read3_ArrayOfSiteQuery()
InnerException:
怎么会这样? "testData" 字符串的内容是:
<SiteQuery><Id>00006000002</Id><UPCPackSize>1</UPCPackSize><UPC_Code>00006000002</UPC_Code><crvId></crvId><dept>8</dept><description>ZZ</description><openQty>0.0</openQty><packSize>1</packSize><subDept>80</subDept><unitCost>1.25</unitCost><unitList>5.0</unitList><vendorId>CONFLICT</vendorId><vendorItem>123456</vendorItem></SiteQuery>
. . . // a ton of other StieQuery records
<SiteQuery><Id>5705654</Id><UPCPackSize>1</UPCPackSize><UPC_Code>5705654</UPC_Code><crvId></crvId><dept>2</dept><description>what do you want</description><openQty>0.0</openQty><packSize>1</packSize><subDept>0</subDept><unitCost>0.55</unitCost><unitList>1.62</unitList><vendorId></vendorId><vendorItem></vendorItem></SiteQuery>
怎么会出现“ XML 文档 (1, 2) 中的错误”?
第 1 行第 2 列是 "S"; "S"怎么了?我想什么都没有,所以它期待什么,因为它也不喜欢 "A"(来自 <ArrayOfSiteQuery
)?
更新 7
我在前面添加了:
<?xml version="1.0" encoding="UTF-8"?>
...到文件,我得到同样的错误,但现在它在 1,40(仍然是第一个“<SiteQuery>
”中的 "S")。
你可以试试这个:
XmlSerializer serializer = new XmlSerializer(typeof(List<SiteMapping>));
XmlReader reader = XmlReader.Create(new StringReader(xmlData));
List<SiteMapping> siteMappings;
siteMappings = (List<SiteMapping>)serializer.Deserialize(reader);
如果可行请告诉我
我有包含 xml 的字符串,我需要循环遍历、解析和构建自定义 classes 的实例,以便插入到我的数据库中。
我需要的伪代码是这样的:
private List<SiteMapping> ExtractSiteMappingsFromXML(String xmlData)
{
List<SiteMapping> sitemaps = new List<SiteMapping>();
// parse xmlData, dynamically instantiating a SiteMapping class for each SiteMapping "record"
in the xml
foreach (record rec in xmlData)
{
SiteMapping sm = new SiteMapping();
sm.Id = //current id found in the xml data
sm.siteName = // current site name found in the xml data
. . .
sitemaps.Add(sm);
}
return sitemaps;
}
ExtractSiteMappingsFromXML() 的调用者将遍历返回的 SiteMapping 列表,并将记录插入数据库。
根据我从 here 那里得到的想法,我认为这样的事情是可能的:
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlData);
XmlNodeList _ids = doc.GetElementsByTagName("Id");
XmlNodeList _sitenames = doc.GetElementsByTagName("siteName");
. . . // add an XmlNodeList for each element
然后我可以遍历 XmlNodeLists,例如:
for (int i = 0; i < _ids.Count; i++)
{
SiteMapping sm = new SiteMapping();
sm.Id =_ids[i];
sm.siteName = _sitenames[i];
. . . // add the rest
sitemaps.Add(sm);
}
这合理吗?如果一个或多个元素具有空白值,这仍然有效吗? IOW,如果一个元素有时是空白的,它会向相应的 XmlNodeList 添加一个空白值(这就是我想要的),还是什么都不添加,从而造成不匹配?
是否有一种优雅的 linqy (LINQ-to-XML) 方式来做到这一点?
注意:这是一个 Compact Framework 应用程序,因此在实施方面受到这些限制。
更新
我想也许这个代码:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(omnivore);
List<SiteQuery> sitequeries =
(from sitequery in xmlDoc.Descendants("SiteQuery")
select new SiteQuery
{
Id = sitequery.Element("Id").Value,
UPC_PackSize = sitequery.Element("UPC_PackSize").Value,
UPC_Code = sitequery.Element("UPC_Code").Value,
}).ToList<SiteQuery>();
...我从 here 改编而来,可以解决问题,但我得到,“方法 'Descendants' 没有重载需要 1 个参数 “
更新 2
我试过了(XDocument 而不是 XmlDocument):
XDocument xmlDoc = new XDocument();
XDocument.Parse(omnivore);
List<SiteQuery> sitequeries =
(from sitequery in xmlDoc.Descendants("SiteQuery")
select new SiteQuery
{
Id = Convert.ToInt32(sitequery.Element("Id").Value),
UPC_PackSize = Convert.ToInt32(sitequery.Element("UPC_PackSize").Value),
UPC_Code = sitequery.Element("UPC_Code").Value
}).ToList<SiteQuery>();
我不得不使用“XDocument.Parse(omnivore);”而不是“xmlDoc.Parse( omnivore);", 但编译器告诉我这是必要的...?!?
不足为奇,在此代码运行后站点查询的计数为 0,但是...
更新 3
也许 Nitin Aggarwal 的代码可以工作(它确实可以编译),但在运行时我得到:
System.InvalidOperationException was unhandled
_HResult=-2146233079
_message=There is an error in XML document (1, 2).
HResult=-2146233079
IsTransient=false
Message=There is an error in XML document (1, 2).
Source=System.Xml
StackTrace:
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader). . .
可能只是XML不好;而且,我不知道这些 jet-age classes 在 Compact Framework 中是否可用(我已经在 .NET 4.5.1 测试应用程序中编译)。
更新 4
Vishal,为了回答您的问题,这是我要解析的 XML:
<ArrayOfSiteQuery xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/CStore.DomainModels.HHS"><SiteQuery><Id>00006000002</Id><UPCPackSize>1</UPCPackSize><UPC_Code>00006000002</UPC_Code><crvId></crvId><dept>8</dept><description>ZZ</description><openQty>0.0</openQty><packSize>1</packSize><subDept>80</subDept><unitCost>1.25</unitCost><unitList>5.0</unitList><vendorId>CONFLICT</vendorId><vendorItem>123456</vendorItem></SiteQuery>
. . . (beaucoup other SiteQuery "records")
<SiteQuery><Id>5705654</Id><UPCPackSize>1</UPCPackSize><UPC_Code>5705654</UPC_Code><crvId></crvId><dept>2</dept><description>what do you want</description><openQty>0.0</openQty><packSize>1</packSize><subDept>0</subDept><unitCost>0.55</unitCost><unitList>1.62</unitList><vendorId></vendorId><vendorItem></vendorItem></SiteQuery></ArrayOfSiteQuery>
是否需要先去掉开头的位(<ArrayOfSiteQuery xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/CStore.DomainModels.HHS">
)和末尾的"close tag"()?
顺便说一句,"CStore.DomainModels.HHS" 在服务器应用程序中,客户端可能不知道那是什么。
更新 5
查看字符串中的xml,发现其内容与我自定义的class不符(是同一个数据,只是部分成员名称不同,彼此乱序),所以我更改了自定义 class 以匹配 xml:
public class SiteQuery
{
public int Id { get; set; }
public int UPCPackSize { get; set; }
public String UPC_Code { get; set; }
public String crvId { get; set; }
public int dept { get; set; }
public String description { get; set; }
public Double openQty { get; set; }
public int packSize { get; set; }
public int subDept { get; set; }
public Decimal unitCost { get; set; }
public Decimal unitList { get; set; }
public String vendorId { get; set; }
public String vendorItem { get; set; }
}
...但我仍然遇到相同的 InvalidOp 异常...
更新 6
甚至在我从 xml 中删除前导码和后导码后,它只包含 SiteQuery "xml records",将其保存为文件并加载它以进行处理:
String testData = File.ReadAllText("siteQueryTest.txt");
XmlSerializer serializer = new XmlSerializer(typeof(List<SiteQuery>));
XmlReader reader = XmlReader.Create(new StringReader(testData));
List<SiteQuery> siteQueries;
siteQueries = (List<SiteQuery>)serializer.Deserialize(reader);
...我仍然收到运行时错误:
System.InvalidOperationException was unhandled
_HResult=-2146233079
_message=There is an error in XML document (1, 2).
HResult=-2146233079
IsTransient=false
Message=There is an error in XML document (1, 2).
Source=System.Xml
StackTrace:
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader)
at Sandbox.Form1.button56_Click(Object sender, EventArgs e) in c:\HoldingTank\Sandbox\Form1.cs:line 2061
. . .
StackTrace:
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderList1.Read3_ArrayOfSiteQuery()
InnerException:
怎么会这样? "testData" 字符串的内容是:
<SiteQuery><Id>00006000002</Id><UPCPackSize>1</UPCPackSize><UPC_Code>00006000002</UPC_Code><crvId></crvId><dept>8</dept><description>ZZ</description><openQty>0.0</openQty><packSize>1</packSize><subDept>80</subDept><unitCost>1.25</unitCost><unitList>5.0</unitList><vendorId>CONFLICT</vendorId><vendorItem>123456</vendorItem></SiteQuery>
. . . // a ton of other StieQuery records
<SiteQuery><Id>5705654</Id><UPCPackSize>1</UPCPackSize><UPC_Code>5705654</UPC_Code><crvId></crvId><dept>2</dept><description>what do you want</description><openQty>0.0</openQty><packSize>1</packSize><subDept>0</subDept><unitCost>0.55</unitCost><unitList>1.62</unitList><vendorId></vendorId><vendorItem></vendorItem></SiteQuery>
怎么会出现“ XML 文档 (1, 2) 中的错误”?
第 1 行第 2 列是 "S"; "S"怎么了?我想什么都没有,所以它期待什么,因为它也不喜欢 "A"(来自 <ArrayOfSiteQuery
)?
更新 7
我在前面添加了:
<?xml version="1.0" encoding="UTF-8"?>
...到文件,我得到同样的错误,但现在它在 1,40(仍然是第一个“<SiteQuery>
”中的 "S")。
你可以试试这个:
XmlSerializer serializer = new XmlSerializer(typeof(List<SiteMapping>));
XmlReader reader = XmlReader.Create(new StringReader(xmlData));
List<SiteMapping> siteMappings;
siteMappings = (List<SiteMapping>)serializer.Deserialize(reader);
如果可行请告诉我