首页 > 解决方案 > 如何从 XML 的特定部分将 XML 序列化为对象?

问题描述

我有问题如何将 XML 序列化为对象列表,但只能从一个大 XML 的特定部分。我的意思是这样的:

仅从项目中获取数据并列出项目对象。

<tXML>
    <nameOfUser>MK</nameOfUser>
    <amouthOfPO>14</amouthOfPO>
    <todayDate></todayDate>
    <warehouses>
        <warehouse id="1">
            <name>AD1</name>
        </warehouse>
        <warehouse id="2">
            <name>AD2</name>
        </warehouse>
        <warehouse id="3">
            <name>AD3</name>
        </warehouse>
    </warehouses>
    <items>
        <warehause id="1">
            <items>
                <item>
                    <name>item1</name>
                    <protectionLevel>AMB</protectionLevel>
                    <description>DescAMB1FORID1</description>
                </item>
                <item>
                    <name>item2</name>
                    <protectionLevel>CHL</protectionLevel>
                    <description>DescCHL1FORID1</description>
                </item>
                <item>
                    <name>item3</name>
                    <protectionLevel>AMB</protectionLevel>
                    <description>3</description>
                </item>
            </items>
        </warehause>
        <warehause id="3">
            <items>
                <item>
                    <name>item1AMB2222</name>
                    <protectionLevel>AMBB222222</protectionLevel>
                    <description>DESCRIPTIONITEM1AM222222B</description>
                </item>
                <item>
                    <name>item222222CHL</name>
                    <protectionLevel>C222222222LL</protectionLevel>
                    <description>ITEM2CH22ILLERAD1</description>
                </item>
                <item>
                    <name>2222222222223</name>
                    <protectionLevel>222222223</protectionLevel>
                    <description>3222222222222</description>
                </item>
            </items>
        </warehause>
        <warehause id="3">
            <items>
                <item>
                    <name>item1333333AMB</name>
                    <protectionLevel>AM3333BB</protectionLevel>
                    <description>DESCR333IPTIONITEM1AMB</description>
                </item>
                <item>
                    <name>item233333CHL</name>
                    <protectionLevel>C33333HLL</protectionLevel>
                    <description>ITEM2CHI333LLERAD1</description>
                </item>
                <item>
                    <name>33</name>
                    <protectionLevel>33</protectionLevel>
                    <description>33</description>
                </item>
            </items>
        </warehause>
    </items>
</tXML>

我的项目类如下所示:

namespace UseFiles
{
    public class Item
    {
        public string Name { get; set; }

        public string ProtectionLevel { get; set; }

        public string Description { get; set; }
    }
}

为对象更改 XML(仅从)的最佳(最佳)方法是什么?我想了两个办法:

  1. xmlSerializer
  2. 或者只是从 XMLNodeList 循环分配值..

标签: c#xmlserialization

解决方案


首先best (optimally) way可以解释为:1 - 最佳性能,2 - 更多(容易)可读的代码。

我想最好的性能应该是FileStream使用XmlReaderand XmlWriter。但在您的情况下,这可能会导致一些额外的并发症,因为items位于内部wherehouses,并且任何item都应该在特定的“wherehouse”内。所以你应该找到具体的项目wherehouse,并在一些更新后将这些项目保存在同一个项目中wherehouse。任何项目都可以是:1 - 更新,2 - 添加,3 - 删除,来自wherehouse,因此现有 xml 文档的更新变得更加复杂。

基于上述,我建议使用LinqToXml它,它的性能效率不高,但在大多数情况下速度足够快,具有您需要的任何工具(搜索和替换具体 xml-tag 中的元素列表)并且更具可读性。

这是您可以使用它的方式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace TestProgram
{
    class Program
    {
        private const string _PATH = @"path to xml-file";

        static void Main(string[] args)
        {
            const string myWherehouseId = "3";
            
            var document = XDocument.Load(_PATH);
            var itemsElement = document.Root.Element("items");

            List<Item> myItems = null;

            foreach (XElement wherehause in itemsElement.Elements())
            {
                if (wherehause.Attribute("id").Value == myWherehouseId)
                {
                    myItems = FromXml(wherehause.Element("items").Elements());

                    // Do some things
                    myItems[0].Name += "1";
                    myItems[0].Description += "2";
                    myItems.RemoveAt(1);
                    myItems.Add(
                        new Item
                        { 
                            Name = "Name212",
                            Description = "Sometext123213",
                            ProtectionLevel = "CHL"
                        });

                    XElement[] updatedElements = ToXml(myItems);

                    // replace old xml nodes with new ones
                    wherehause.Element("items").ReplaceNodes(updatedElements);
                    break;
                }
            }

            document.Save(_PATH);
        }

        public static List<Item> FromXml(IEnumerable<XElement> elements)
        {
            // you could use any custom mapper for conversion from XElement to Item
            return elements.Select(el => new Item
            {
                Name = el.Element("name").Value,
                ProtectionLevel = el.Element("protectionLevel").Value,
                Description = el.Element("description").Value                
            }).ToList();
        }

        public static XElement[] ToXml(List<Item> items)
        {
            // you could use any custom mapper for conversion from Item to XElement
            return items
                .Select(item => 
                    new XElement("item", 
                        new XElement("name", item.Name),
                        new XElement("protectionLevel", item.ProtectionLevel),
                        new XElement("description", item.Description)))
                .ToArray();
        }
    }

    public class Item
    {
        public string Name { get; set; }

        public string ProtectionLevel { get; set; }

        public string Description { get; set; }
    }
}

在我看来best (optimally) way,包括性能和代码可读性之间的合理折衷。

这是我最好的方法;)


推荐阅读