通过LINQ从XML文档填充自定义List子类 [英] Populate custom List sub class from XML document via LINQ

查看:46
本文介绍了通过LINQ从XML文档填充自定义List子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经弄清楚了如何从XML数据中填充自定义类,但是在此过程中遇到了一个问题.一切都与我现有的填充数据方法完美地结合在一起,直到我被扔了一点曲线球为止.我收到的新架构与此类似:

I have figured out how to populate a custom class from XML data, but I ran into an issue along the way. Things were working perfectly with my existing method of populating data until I was thrown a bit of a curve ball. The new schema I was sent is similar to this:

<ITEM_REPLY>
<TRAN_ID>1320691307345</TRAN_ID>
<REPLY_CODE>0</REPLY_CODE>
<UNIT_PRICE>8.2784</UNIT_PRICE>
<SUP_LOCS>
  <SUP_LOC>
     <SUP_LOC_ID>001134</SUP_LOC_ID>
     <COUNTRY_ID>USA</COUNTRY_ID>
     <QTY_AVL>47.000</QTY_AVL>
     <ITEM_UOM>EA</ITEM_UOM>
  </SUP_LOC>
  <SUP_LOC>
     <SUP_LOC_ID>006817</SUP_LOC_ID>
     <COUNTRY_ID>USA</COUNTRY_ID>
     <QTY_AVL>20.000</QTY_AVL>
     <ITEM_UOM>EA</ITEM_UOM>
  </SUP_LOC>
</SUP_LOCS>
<MESSAGE />
<QTY_BREAKS />
</ITEM_REPLY>

相当标准的XML模式,问题是我不确定如何用它填充自定义类.这就是我所拥有的:

Pretty standard XML schema, problem is I'm not sure how to populate my custom class with it. Here's what I do have:

static void Main(string[] args)
{
    var order = ConvertXMLMessage<ItemReply>(request);
}

protected static T ConvertXMLMessage<T>(String xmlData) where T : class, new()
{
    var xml = new XmlDocument();
    xml.LoadXml(xmlData);

    var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));

    using (var xmlReader = new XmlNodeReader(xml.DocumentElement))
    {
        T work = (T)(serializer.Deserialize(xmlReader));
        return work;
    }
}

public class ItemReply
{
    [XmlElement("ITEM_REPLY")]
    public ItemAvlReply ITEM_REPLY { get; set; }
}
public class ItemAvlReply
{
    [XmlElement("TRAN_ID")]
    public string TRAN_ID { get; set; }
    [XmlElement("REPLY_CODE")]
    public string REPLY_CODE { get; set; }
    [XmlElement("UNIT_PRICE")]
    public string UNIT_PRICE { get; set; }
    [XmlElement("SUP_LOCS")]
    public SupplierLocations SUP_LOCS;
    [XmlElement("MESSAGE")]
    public string MESSAGE { get; set; }
    [XmlElement("QTY_BREAKS")]
    public string QTY_BREAKS { get; set; }
}
public class SupplierLocations
{
    [XmlElement("SUP_LOC")]
    public List<SupplierLocation> SUP_LOC;
}
public class SupplierLocation
{
    [XmlElement("SUP_LOC_ID")]
    public string SUP_LOC_ID { get; set; }
    [XmlElement("COUNTRY_ID")]
    public string COUNTRY_ID { get; set; }
    [XmlElement("QTY_AVL")]
    public string QTY_AVL { get; set; }
    [XmlElement("ITEM_UOM")]
    public string ITEM_UOM { get; set; }
}

这很好地减去了List<Item>部分.我对LINQ并没有过多的经验,也不确定如何通过此语句在类中声明子数组.我也对创建List<Item>部分不同的方法持开放态度,只是不确定从何处开始.我需要做的更好的方法吗?在LINQ中我没有意识到一个简单的解决方案吗?

This works perfectly minus the List<Item> part. I'm not overly experienced with LINQ and I'm not sure how to go about declaring a sub array in my class via this statement. I am also open to a different approach from creating the List<Item> part, I'm just not sure where to start otherwise. Is there a better approach for what I'm need to do? Is there an easy solution I am just unaware of in LINQ?

推荐答案

这里是一种简单的方法,假设您提供的示例XML文件有错字.我假设OrderId具有结束标记,并且Items的结束标记应为/Items.

Here's a simple way to do it, assuming the example XML file you provided has typos. I assumed the OrderId has a closing tag, and that the closing tag for Items should be /Items.

这是我使用的xml版本:

Here's the version of the xml I used:

<Order>
<TransactionID>123</TransactionID>
<OrderID>1</OrderID>
<Items Number="2">
    <Item>
        <ItemName>Test</ItemName>
        <Color>Red</Color>
    </Item>
    <Item>
        <ItemName>Test1</ItemName>
        <Color>Blue</Color>
    </Item>
</Items>
</Order>

以下是读取/写入XML的代码:(xml变量是一个字符串)

Here's the code to read/write the XML: (the xml variable is a String)

var order = ConvertXMLMessage<Order>(xml);
WriteXMLFile<Order>(order, @"test.xml");

这是ConvertXMLMessage和WriteXMLFile函数:

Here's the ConvertXMLMessage and WriteXMLFile functions:

protected static T ConvertXMLMessage<T>(String xmlData) where T : class, new()
{
    var xml = new XmlDocument();
    xml.LoadXml(xmlData);

    var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));

    using (var xmlReader = new XmlNodeReader(xml.DocumentElement))
    {
        T work = (T)(serializer.Deserialize(xmlReader));
        return work;
    }
}

protected static void WriteXMLFile<T>(T item, String saveLocation) where T : class, new()
{
    System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(T));

    System.IO.StreamWriter file = new System.IO.StreamWriter(saveLocation);
    writer.Serialize(file, item);
    file.Close();
}

这是类结构:

public class Order
{
    [XmlElement("TransactionID")]
    public string TransactionId { get; set; }
    [XmlElement("OrderID")]
    public string OrderId { get; set; }
    [XmlElement("Items")]
    public ItemsContainer Items;
}

public class ItemsContainer
{
    [XmlAttribute("Number")]
    public Int32 Number { get; set; }

    [XmlElement("Item")]
    public List<Item> Items;
}

public class Item
{
    [XmlElement("ItemName")]
    public string ItemName { get; set; }
    [XmlElement("Color")]
    public string Color { get; set; }
}

您会注意到,我添加了一些属性,以使XML解析器知道在从XML转换为XML时如何处理该类.我还添加了另一个名为"ItemsContainer"的小类,仅用于保存Items标记上的详细信息.如果您不需要"Number"属性,那么您可能可以找到一种解决方法.但是,这应该可以引导您正确的方向.

As you'll notice I added some attributes to let the XML parser know how to handle the class when it's converting from/to the XML. I also added another small class called "ItemsContainer" just to hold the details on the Items tag. If you didn't need the "Number" attribute, then you could probably find a way to do away with this. However, this should get you in the right direction.

我提供的示例是我通常如何处理这种情况的简单版本,显然,您可以根据需要进行一些改进.

The example I provided is a simple version of how I usually handle the situation, obviously there's some improvements you can make depending on your needs.

修改 我将Item类更改为使用ItemName而不是TransactionId.这是我的疏忽.

Edit I changed the Item class to use ItemName instead of TransactionId. It was an oversight on my part.

编辑2 这是您需要对新发布的代码进行的更正. Order类在上一个示例中起作用的原因是它与根XML元素匹配.您是新的XML确实与基类保持一致.因此,我们需要添加更多的属性才能使它工作.您也可以删除ItemReply类.不需要.

Edit 2 Here's the corrections you need to make to the newly posted code. The reason the Order class worked in the previous example was it matched the root XML element. You're new XML does align with the base class. So we need to add in a couple more attributes to make this work. You can also remove your ItemReply class. It's not needed.

这是新的类:

[XmlRoot("ITEM_REPLY")]
public class ItemAvlReply
{
    [XmlElement("TRAN_ID")]
    public string TRAN_ID { get; set; }
    [XmlElement("REPLY_CODE")]
    public string REPLY_CODE { get; set; }
    [XmlElement("UNIT_PRICE")]
    public string UNIT_PRICE { get; set; }
    [XmlElement("SUP_LOCS")]
    public SupplierLocations SUP_LOCS;
    [XmlElement("MESSAGE")]
    public string MESSAGE { get; set; }
    [XmlElement("QTY_BREAKS")]
    public string QTY_BREAKS { get; set; }
}
public class SupplierLocations
{
    [XmlElement("SUP_LOC")]
    public List<SupplierLocation> SUP_LOC;
}
public class SupplierLocation
{
    [XmlElement("SUP_LOC_ID")]
    public string SUP_LOC_ID { get; set; }
    [XmlElement("COUNTRY_ID")]
    public string COUNTRY_ID { get; set; }
    [XmlElement("QTY_AVL")]
    public string QTY_AVL { get; set; }
    [XmlElement("ITEM_UOM")]
    public string ITEM_UOM { get; set; }
}

其他所有内容都应保持不变.将XML解析/转换为类应该可以正常工作.

Everything else should remain the same. The parsing/converting the XML to classes should work without any changes.

这篇关于通过LINQ从XML文档填充自定义List子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆