2010-07-27 83 views
1

我正在开发一个系统,通过Exchange Web服务从电子邮件中提取XML附件,并通过我创建的自定义DAL对象将它们输入到数据库中。解析XML文件-options?

我已经设法提取XML附件并将其准备好作为流...他们的问题是如何解析此流并填充DAL对象。

我可以创建一个XMLTextReader并遍历每个元素。除此之外,我没有看到任何问题,我怀疑有一种很滑的方式。阅读器似乎将开始标签,标签的内容和结束标签视为不同的元素(使用reader.NodeType)。我预计我的价值被认为是一个元素而不是三个。就像我说的,我可以解决这个问题,但我相信肯定有更好的方法。

我遇到了使用XML序列化器(对我来说是全新的)的想法,但快速查看表明这些不能处理ArrayLists和List(我正在使用List)。

再一次,我是LINQ的新手,但也提到了LINQ到XML,但我看过的例子看起来相当复杂 - 尽管我只是缺乏熟悉感。

基本上,我不想要一个封闭的系统,但我不想使用任何复杂的技术与学习曲线,只是因为它'很酷'。

将此XML/Stream转换为我的DAL对象的最简单和最有效的方法是什么?

XML示例:

<?xml version="1.0" encoding="UTF-8"?> 
<enquiry> 
    <enquiryno>100001</enquiryno> 
    <companyname>myco</companyname> 
    <typeofbusiness>dunno</typeofbusiness> 
    <companyregno>ABC123</companyregno> 
    <postcode>12345</postcode> 
    <contactemail>[email protected]</contactemail> 
    <firstname>My</firstname> 
    <lastname>Name</lastname> 
    <vehicles> 
     <vehicle> 
      <vehiclereg>54321</vehiclereg> 
      <vehicletype>Car</vehicletype> 
      <vehiclemake>Ford</vehiclemake> 
      <cabtype>n/a</cabtype> 
      <powerbhp>130</powerbhp> 
      <registrationdate>01/01/2003</registrationdate> 
     </vehicle> 
    </vehicles> 
</enquiry> 

更新1: 我试图反序列化的基础上,格雷厄姆的例子。我认为我已经设置了序列化的DAL,包括为每个属性指定[XmlElement("whatever")]。我已经尝试使用反序列化如下:

SalesEnquiry enquiry = null; 
XmlSerializer serializer = new XmlSerializer(typeof(SalesEnquiry)); 
enquiry = (SalesEnquiry)serializer.Deserialize(stream); 

但是,我得到一个异常:“There is an error in XML document (2, 2)”。设置InnerException指出{"<enquiry xmlns=''> was not expected."}

结论(更新):

我以前的问题是一个事实,即XML文件(查询)中的元素=类(SalesEnquiry)这个名字!而不是该类的[XmlElement]属性,我们需要改为[XmlRoot]属性。为了完整起见,如果您希望在序列化过程中忽略班级中的某个属性,请使用[XmlIgnore]属性。

我已成功序列化了我的对象,并且现在已成功接收传入的XML并将其解序列化为SalesEnquiry对象。

这种方法比手动解析XML要容易得多。好吧,学习曲线陡峭,但是值得。

谢谢!

+1

XML附件是否符合特定模式?它总是一样的模式?您是否将XML“分解”为特定的表格布局,或将整个文档存储为BLOB? – lesscode 2010-07-27 11:51:41

+0

@Wayne:不,没有正式的模式,一些元素是可选的,将会丢失而不是空白。数据存储在数据库中的一对表中。 – CJM 2010-07-27 13:46:49

+0

我已根据您的更新更新了我的答案。 – 2010-07-27 14:44:18

回答

6

如果您的XML使用模式(即您总是会知道显示的元素以及它们在树中的显示位置),您可以使用XmlSerializer来创建对象。您只需在您的类上使用一些属性来告诉序列化程序它们对应的XML元素或属性。然后,只需加载XML,使用要创建的.NET对象的类型创建一个新的XmlSerializer,然后调用Deserialize方法。

例如,你有一个这样的类:

[Serializable] 
public class Person 
{ 
    [XmlElement("PersonName")] 
    public string Name { get; set; } 

    [XmlElement("PersonAge")] 
    public int Age { get; set; } 

    [XmlArrayItem("Child")] 
    public List<string> Children { get; set; } 
} 

输入这样的XML(保存在文件中的这个例子):

<?xml version="1.0"?> 
<Person> 
    <PersonName>Bob</PersonName> 
    <PersonAge>35</PersonAge> 
    <Children> 
    <Child>Chris</Child> 
    <Child>Alice</Child> 
    </Children> 
</Person> 

然后创建一个Person例如像这样的:

Person person = null; 
XmlSerializer serializer = new XmlSerializer(typeof(Person)); 
using (FileStream fs = new FileStream(GetFileName(), FileMode.Open)) 
{ 
    person = (Person)serializer.Deserialize(fs); 
} 

更新: 根据你最近的更新,我猜想你要么指定一个XmlRoot属性作为你的根元素。 SalesEnquiry)或XmlSerializer可能有点困惑,因为您在XML中引用了一个空的名称空间(xmlns=''看起来不正确)。

+0

一旦我得到这个工作(见上文),这应该是非常方便,谢谢。 – CJM 2010-07-27 14:30:55

+0

我试着为该类指定一个XmlElement属性,但它不允许它。此外,我尝试添加一个名称空间到查询元素,并在同一点发生同样的错误。我很难过。 – CJM 2010-07-27 15:13:53

+0

@CJM,对不起,我的错误:它不是您在课堂上需要的'XmlElement',而是'XmlRoot'。我已经更新了我的答案。 – 2010-07-28 08:33:52

2

XmlSerializer确实支持数组&列表...只要包含的类型是可序列化的。

1

我发现Xsd2Code对这种事情非常有帮助:http://xsd2code.codeplex.com/

基本上,所有你需要做的是写一个XSD文件(XML模式文件),并指定一些命令行开关。 Xsd2Code会自动生成一个C#类文件,其中包含所有类和属性以及处理序列化所需的所有内容。这不是一个完美的解决方案,因为它不支持XSD的所有方面,但是如果你的XML文件是相对简单的元素和属性集合,它应该是一个很好的捷径。

Codeplex上还有另外一个类似的项目叫做Linq to XSD(http://linqtoxsd.codeplex.com/),它被设计用于强制执行整个XSD规范,但上次我检查时,它不再被支持,也没有准备好黄金时段。不过,我认为这值得一提。

+0

谢谢丹 - 可能早些时候有用,但无论出于何种原因,我创建了DAL,然后链接回XML。如果这个应用程序是它的东西,它可能会让这个过程更加快捷。另一方面,这是一个有价值的学习练习,因为它是...... – CJM 2010-07-27 21:39:06