【问题标题】:Populate custom List sub class from XML document via LINQ通过 LINQ 从 XML 文档填充自定义 List 子类
【发布时间】:2014-11-06 16:48:34
【问题描述】:

我已经弄清楚如何从 XML 数据填充自定义类,但在此过程中遇到了一个问题。事情与我现有的填充数据的方法完美配合,直到我被抛出了一点曲线球。我收到的新架构类似于:

<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 模式,问题是我不确定如何用它填充我的自定义类。这是我所拥有的:

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&lt;Item&gt; 部分。我对 LINQ 并没有过多的经验,我不确定如何通过这个语句在我的类中声明一个子数组。我也对创建List&lt;Item&gt; 部分的不同方法持开放态度,我只是不确定从哪里开始。对于我需要做的事情,有更好的方法吗?在 LINQ 中是否有我不知道的简单解决方案?

【问题讨论】:

    标签: c# xml linq


    【解决方案1】:

    这是一个简单的方法,假设您提供的示例 XML 文件有拼写错误。我假设 OrderId 有一个结束标记,Items 的结束标记应该是 /Items

    这是我使用的 xml 版本:

    <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 变量是一个字符串)

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

    这是 ConvertXMLMessage 和 WriteXMLFile 函数:

    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 之间的转换时如何处理它。我还添加了另一个名为“ItemsContainer”的小类,只是为了保存 Items 标记的详细信息。如果您不需要“数字”属性,那么您可能会找到一种方法来消除它。但是,这应该会让您朝着正确的方向前进。

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

    编辑 我将 Item 类更改为使用 ItemName 而不是 TransactionId。这是我的疏忽。

    编辑 2 这是您需要对新发布的代码进行的更正。 Order 类在上一个示例中起作用的原因是它与根 XML 元素匹配。你是新的 XML 确实与基类一致。所以我们需要添加更多的属性来完成这项工作。您还可以删除您的 ItemReply 类。不需要。

    所以这是新的类:

    [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 解析/转换为类应该无需任何更改即可工作。

    【讨论】:

    • 我收到错误There is an error in the XML document.
    • 你能再给我一点继续吗?你在使用我提供的 XML(我从原来的部分更改了一些部分,因为它看起来有错别字)?您使用的是什么 .Net 框架?我已经在测试控制台作业中运行了上面的代码,没有任何错误。我正在使用.Net 4.5。如果您使用相同的框架并测试 XML,那么我需要查看您实现的代码。
    • 我将彻底改变上述问题。我发布了一个“愚蠢”的 xml 和类定义,只是为了表达我的观点。给我一秒钟,如果有任何问题,你可以告诉我。
    • 已更新。这也是确切的错误{System.InvalidOperationException: &lt;ITEM_REPLY xmlns=''&gt; was not expected.at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderItemReply.Read6_ItemReply()}
    • 我在答案中添加了一个编辑以充分解释问题,但归结为根 XML 标记与您的类名不匹配。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多