如何正确设置 class 结构以正确反序列化 XML?
How to properly setup a class structure to properly de-serialize XML?
--更新--
其实再看一遍代码,我应该改一下问题。在下面添加了更多说明。
我有一个从 Web 服务返回的 XML 结构,应该是标准问题 cXML 结构。我的问题是一个重复的 <Extrinsic>
节点,它有一个参数名称,除了区分它们的值之外。
像这样:
<ItemDetail>
<UnitPrice>
<Money currency="USD">1.53 </Money>
</UnitPrice>
<Description>ASPIRIN 81 MG CHW 90</Description>
<UnitOfMeasure>EA</UnitOfMeasure>
<Extrinsic name="HCustomerNumber">0100074080</Extrinsic>
<Extrinsic name="HPONumber">201</Extrinsic>
<Extrinsic name="HOrderNumber">4413686057</Extrinsic>
<Extrinsic name="HUserID">ABTGDEV</Extrinsic>
<Extrinsic name="HLegacyCustomerNumber">055150912</Extrinsic>
<Extrinsic name="LegacyItemNumber">198440</Extrinsic>
<Extrinsic name="CustomerMaterialNumber"/>
<Extrinsic name="ContractNumber"/>
<Extrinsic name="NDC">00904628889</Extrinsic>
<Extrinsic name="UPC">309046288893</Extrinsic>
<Extrinsic name="Size">90</Extrinsic>
<Extrinsic name="DrugFormPackSize">90.000</Extrinsic>
<Extrinsic name="Prevent Sub">False</Extrinsic>
<Extrinsic name="SHCCode"/>
<Extrinsic name="DEPTCode"/>
<Extrinsic name="GLCode"/>
<Extrinsic name="SWP">3.62000</Extrinsic>
<Extrinsic name="RetailPrice">0.00</Extrinsic>
<Extrinsic name="RetailPriceOverride">0.00</Extrinsic>
<Extrinsic name="TemporaryRetailPriceOverride">True</Extrinsic>
<Extrinsic name="UDIF"/>
<Extrinsic name="UDIFDesc"/>
<Extrinsic name="Formulary"/>
<Extrinsic name="SPLRouting"/>
</ItemDetail>
如何设置我的 class 结构以便正确反序列化? class 本身由 PetaPoco 渲染,因此每个 <Extrinsic>
节点都是数据库中 class/field 的 属性。或者做不出来,需要手动处理,我一直在苦苦思索,一直没有找到好的自动化方式。
--更新--
这就是我要反序列化为
的 class
public int syspohid { get; set; }
public int syspodid { get; set; }
public string pdvendor { get; set; }
public string pdprefix { get; set; }
public Nullable<int> pdnumber { get; set; }
public Nullable<int> pdline { get; set; }
public bool pdtaxable { get; set; }
public bool pdfreightable { get; set; }
public string comments { get; set; }
public string pdlocation { get; set; }
public string pddoctor { get; set; }
public string pdpatient { get; set; }
public string pdlotnum { get; set; }
public Nullable<System.DateTime> pdcasedate { get; set; }
public bool pduseany { get; set; }
public string pdvnitemid { get; set; }
public string pdvnuofm { get; set; }
public Nullable<int> pdvnunit { get; set; }
public string pddescript { get; set; }
public Nullable<decimal> pdvnprice { get; set; }
public Nullable<int> pdvnqty { get; set; }
public Nullable<int> pdrcvtype { get; set; }
public string pdrcvline { get; set; }
public Nullable<int> sysprdid { get; set; }
public Nullable<int> pdvnorgqty { get; set; }
public Nullable<int> sysshipid { get; set; }
public string shipid { get; set; }
public string shipdesc { get; set; }
public string pdgl { get; set; }
public Nullable<System.DateTime> pdshipdt { get; set; }
public string pdinternalid { get; set; }
public string pdmanufacid { get; set; }
public string pdndc { get; set; }
public string pdpatchargeid { get; set; }
public string pdupn { get; set; }
public string entitycode { get; set; }
public string deptcode { get; set; }
public string classcode { get; set; }
public string expencode { get; set; }
public string cadduser { get; set; }
public Nullable<System.DateTime> dadd { get; set; }
public string cedituser { get; set; }
public Nullable<System.DateTime> dedit { get; set; }
public Nullable<decimal> taxpct { get; set; }
public Nullable<int> invoiceqty { get; set; }
public string auditinfo { get; set; }
public string totenumber { get; set; }
public string export { get; set; }
public Nullable<int> scheduledDrugIndex { get; set; }
public string contractid { get; set; }
public string refnum { get; set; }
然后真正的问题就变成了,如何使用属性 name 的值来正确反序列化 xml。有可能吗?
谢谢。
一种可能是使用 xsd.exe
D:\WorkSpace\dump>xsd myxml.xml
甚至可以使用
等在线工具进行下一步
http://www.httputility.net/xsd-to-csharp-vb-class.aspx
在适当的 xml 文件的情况下,这将生成易于使用的 C# 类 供 System.XML.Serialization.XMLSerializer 读写 XML
如果您为返回的 xml 文件定义一个 XML 模式 (.xsd) 文件,您可以生成 classes 与 XSD.exe 命令行工具。
或者,
如果是我,我根本不会反序列化它。相反,我会用 XDocument/XElement 对象等
来解析它
例如,我会为所有内容手动创建 classes 并为它们提供更好的功能,例如,
public enum CurrencyType
{
USD = 0,
EUR = 1 //etc..
}
public class Money
{
public CurrencyType CurrenyType { get; set; }
public decimal Value { get; set; }
public Money(XElement element)
{
if (element.Name.LocalName != "Money")
throw new Exception(...);
var aCurrency = element.Attribute("currency");
this.CurrencyType = aCurrency == null || string.IsNullOrEmpty(aCurrency.Value) ? CurrencyType.USD : (CurrencyType)Enum.Parse(typeof(CurrencyType), aCurrency.Value);
this.Value = element != null && !string.IsNullOrEmpty(element.Value) ? element.Value : 0;
}
}
我会为每个复杂的子元素制作一个。然后我会制作一个名为 ItemDetail 的主要内容,它将那些 classes 作为属性公开。在 ItemDetail 的构造函数中,我会将 xml 加载到一个元素,获取金钱节点,并使用金钱节点的 XElement 实例化金钱 class,等等
我通常走这条路,因为反序列化会给你一个字符串列表或你的外部节点的字典,我发现这是针对它的复杂编码。通过我自己手动完成,我可以为每个外部值创建属性,而无需找出复杂的属性映射规则来让反序列化器执行此操作。这样做通常会产生更好的代码(更容易理解和使用)并且更灵活。
--更新--
其实再看一遍代码,我应该改一下问题。在下面添加了更多说明。
我有一个从 Web 服务返回的 XML 结构,应该是标准问题 cXML 结构。我的问题是一个重复的 <Extrinsic>
节点,它有一个参数名称,除了区分它们的值之外。
像这样:
<ItemDetail>
<UnitPrice>
<Money currency="USD">1.53 </Money>
</UnitPrice>
<Description>ASPIRIN 81 MG CHW 90</Description>
<UnitOfMeasure>EA</UnitOfMeasure>
<Extrinsic name="HCustomerNumber">0100074080</Extrinsic>
<Extrinsic name="HPONumber">201</Extrinsic>
<Extrinsic name="HOrderNumber">4413686057</Extrinsic>
<Extrinsic name="HUserID">ABTGDEV</Extrinsic>
<Extrinsic name="HLegacyCustomerNumber">055150912</Extrinsic>
<Extrinsic name="LegacyItemNumber">198440</Extrinsic>
<Extrinsic name="CustomerMaterialNumber"/>
<Extrinsic name="ContractNumber"/>
<Extrinsic name="NDC">00904628889</Extrinsic>
<Extrinsic name="UPC">309046288893</Extrinsic>
<Extrinsic name="Size">90</Extrinsic>
<Extrinsic name="DrugFormPackSize">90.000</Extrinsic>
<Extrinsic name="Prevent Sub">False</Extrinsic>
<Extrinsic name="SHCCode"/>
<Extrinsic name="DEPTCode"/>
<Extrinsic name="GLCode"/>
<Extrinsic name="SWP">3.62000</Extrinsic>
<Extrinsic name="RetailPrice">0.00</Extrinsic>
<Extrinsic name="RetailPriceOverride">0.00</Extrinsic>
<Extrinsic name="TemporaryRetailPriceOverride">True</Extrinsic>
<Extrinsic name="UDIF"/>
<Extrinsic name="UDIFDesc"/>
<Extrinsic name="Formulary"/>
<Extrinsic name="SPLRouting"/>
</ItemDetail>
如何设置我的 class 结构以便正确反序列化? class 本身由 PetaPoco 渲染,因此每个 <Extrinsic>
节点都是数据库中 class/field 的 属性。或者做不出来,需要手动处理,我一直在苦苦思索,一直没有找到好的自动化方式。
--更新--
这就是我要反序列化为
的 class public int syspohid { get; set; }
public int syspodid { get; set; }
public string pdvendor { get; set; }
public string pdprefix { get; set; }
public Nullable<int> pdnumber { get; set; }
public Nullable<int> pdline { get; set; }
public bool pdtaxable { get; set; }
public bool pdfreightable { get; set; }
public string comments { get; set; }
public string pdlocation { get; set; }
public string pddoctor { get; set; }
public string pdpatient { get; set; }
public string pdlotnum { get; set; }
public Nullable<System.DateTime> pdcasedate { get; set; }
public bool pduseany { get; set; }
public string pdvnitemid { get; set; }
public string pdvnuofm { get; set; }
public Nullable<int> pdvnunit { get; set; }
public string pddescript { get; set; }
public Nullable<decimal> pdvnprice { get; set; }
public Nullable<int> pdvnqty { get; set; }
public Nullable<int> pdrcvtype { get; set; }
public string pdrcvline { get; set; }
public Nullable<int> sysprdid { get; set; }
public Nullable<int> pdvnorgqty { get; set; }
public Nullable<int> sysshipid { get; set; }
public string shipid { get; set; }
public string shipdesc { get; set; }
public string pdgl { get; set; }
public Nullable<System.DateTime> pdshipdt { get; set; }
public string pdinternalid { get; set; }
public string pdmanufacid { get; set; }
public string pdndc { get; set; }
public string pdpatchargeid { get; set; }
public string pdupn { get; set; }
public string entitycode { get; set; }
public string deptcode { get; set; }
public string classcode { get; set; }
public string expencode { get; set; }
public string cadduser { get; set; }
public Nullable<System.DateTime> dadd { get; set; }
public string cedituser { get; set; }
public Nullable<System.DateTime> dedit { get; set; }
public Nullable<decimal> taxpct { get; set; }
public Nullable<int> invoiceqty { get; set; }
public string auditinfo { get; set; }
public string totenumber { get; set; }
public string export { get; set; }
public Nullable<int> scheduledDrugIndex { get; set; }
public string contractid { get; set; }
public string refnum { get; set; }
然后真正的问题就变成了,如何使用属性 name 的值来正确反序列化 xml。有可能吗?
谢谢。
一种可能是使用 xsd.exe
D:\WorkSpace\dump>xsd myxml.xml
甚至可以使用
等在线工具进行下一步http://www.httputility.net/xsd-to-csharp-vb-class.aspx
在适当的 xml 文件的情况下,这将生成易于使用的 C# 类 供 System.XML.Serialization.XMLSerializer 读写 XML
如果您为返回的 xml 文件定义一个 XML 模式 (.xsd) 文件,您可以生成 classes 与 XSD.exe 命令行工具。
或者,
如果是我,我根本不会反序列化它。相反,我会用 XDocument/XElement 对象等
来解析它例如,我会为所有内容手动创建 classes 并为它们提供更好的功能,例如,
public enum CurrencyType
{
USD = 0,
EUR = 1 //etc..
}
public class Money
{
public CurrencyType CurrenyType { get; set; }
public decimal Value { get; set; }
public Money(XElement element)
{
if (element.Name.LocalName != "Money")
throw new Exception(...);
var aCurrency = element.Attribute("currency");
this.CurrencyType = aCurrency == null || string.IsNullOrEmpty(aCurrency.Value) ? CurrencyType.USD : (CurrencyType)Enum.Parse(typeof(CurrencyType), aCurrency.Value);
this.Value = element != null && !string.IsNullOrEmpty(element.Value) ? element.Value : 0;
}
}
我会为每个复杂的子元素制作一个。然后我会制作一个名为 ItemDetail 的主要内容,它将那些 classes 作为属性公开。在 ItemDetail 的构造函数中,我会将 xml 加载到一个元素,获取金钱节点,并使用金钱节点的 XElement 实例化金钱 class,等等
我通常走这条路,因为反序列化会给你一个字符串列表或你的外部节点的字典,我发现这是针对它的复杂编码。通过我自己手动完成,我可以为每个外部值创建属性,而无需找出复杂的属性映射规则来让反序列化器执行此操作。这样做通常会产生更好的代码(更容易理解和使用)并且更灵活。