在父元素内将对象序列化为 XML [英] Serialize object to XML WITHIN a parent element

查看:47
本文介绍了在父元素内将对象序列化为 XML的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 WPF C# 程序,有一次我需要将对象序列化为 XML.在其他地方,我一直在使用这个:

I've got a WPF C# program and at one point I need to serialize objects to XML. In other places, I've been using this:

TextWriter writer = new StreamWriter(xmlFilePath);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MYOBJECT_TYPE));

try
{
    xmlSerializer.Serialize(writer, MYOBJECT);

}
catch (Exception ex)
{
    MessageBox.Show("Exception occured while writing to Xml" + ex.Message);
}
finally
{
    writer.Close();
}

这太棒了,但这意味着我必须为每个要序列化的对象使用不同的 XML 文件.如何使用此方法(以最少的修改)将对象序列化为 XML WITHIN 父元素?这样,当我稍后想反序列化对象时,我可以找到我想要的元素,然后反序列化该元素中的所有内容.

This is fantastic, but this means I have to have a different XML file for every object I want to serialize. How do I use this method (with the least amount of modifications) to serialize the object to the XML WITHIN a parent element? That way, when I want to deserialize the object later, I can just find the element that I want, and deserialize everything within that element.

根据要求,这里是 CreateDefaultXml();:

static void CreateDefaultXml()
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml("<StoredObjects></StoredObjects>");
    XmlNode root = doc.DocumentElement;
    try
    {
        doc.Save(xmlFilePath);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception occured while creating Xml" + ex.InnerException);
    }
}

目前,这就是我所得到的(但它抛出异常生成 XML 文档时出错.)

Currently, this is what I've got (but it throws an exception There was an error generating the XML document.)

if (!File.Exists(xmlFilePath))
    CreateDefaultXml();

XDocument doc = XDocument.Load(xmlFilePath);
var element = doc.Descendants("Object").Where(x => x.Attribute("Name").Value.Equals("objectName")).SingleOrDefault();

if (element == null)
{
    element = new XElement("Object", new XAttribute("Name", objectName));
    doc.Element("StoredObjects").Add(element);
}

XmlWriter writer = element.CreateWriter();
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MYOBJECT_TYPE));

try
{
    xmlSerializer.Serialize(writer, MYOBJECT);

}
catch (Exception ex)
{
    MessageBox.Show("Exception occured while writing to Xml: " + ex.Message);
}
finally
{
    writer.Close();
    doc.Save(xmlFilePath);
}

推荐答案

您正在尝试使用 XmlSerializer<直接序列化到 XDocument 内的某些嵌套 XElement/代码>.不幸的是,当使用 XmlSerializerXContainer.CreateWriter(),实际需要序列化为空XDocument 从而创建其根元素.(我不确定为什么这个限制存在,但确实存在.)由于这不符合您的需求,很容易序列化为 temporary XDocument,删除它的根节点,然后将该节点添加到整个元素层次结构中.

You are trying to serialize directly to some nested XElement inside an XDocument using XmlSerializer. Unfortunately, it seems that, when serializing directly to a LINQ-to-XML XElement using XmlSerializer together with XContainer.CreateWriter(), it is actually necessary to serialize to an empty XDocument thereby creating its root element. (I am not sure why this restriction exists, but it does.) Since this doesn't meet your needs, it is easy to serialize to a temporary XDocument, remove its root node, then add that node to your overall element hierarchy.

此外,当使用已存储 XML 数据的 objectName 向数据库添加对象时,您需要删除旧数据.

Also, when adding an object to your database using an objectName that already has XML data stored, you need to remove the old data.

我将您的代码重构为扩展方法以实现此目的:

I refactored your code into extension methods to accomplish this:

public static class XmlExtensions
{
    public static T Deserialize<T>(this XContainer element, XmlSerializer serializer = null)
    {
        using (var reader = element.CreateReader())
        {
            object result = (serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
            if (result is T)
                return (T)result;
        }
        return default(T);
    }

    public static XElement SerializeToXElement<T>(this T obj, XmlSerializer serializer = null)
    {
        var doc = new XDocument();
        using (var writer = doc.CreateWriter())
            (serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj);
        var element = doc.Root;
        if (element != null)
            element.Remove();
        return element;
    }

    public static XName ContainerElementName { get { return (XName)"Object"; } }

    public static XName ContainerAttributeName { get { return (XName)"Name"; } }

    public static XElement SetItem<T>(this XDocument doc, string attributeValue, T obj)
    {
        return doc.SetItem(ContainerElementName, ContainerAttributeName, attributeValue, obj);
    }

    static XElement SetItem<T>(this XDocument doc, XName containerElementName, XName containerAttributeName, string attributeValue, T obj)
    {
        if (doc == null || containerElementName == null || containerAttributeName == null || attributeValue == null)
            throw new ArgumentNullException();
        if (doc.Root == null)
            throw new ArgumentException("doc.Root == null");
        var container = doc.Root.Elements(containerElementName).Where(e => (string)e.Attribute(containerAttributeName) == attributeValue).SingleOrDefault();
        if (container == null)
        {
            container = new XElement(containerElementName, new XAttribute(containerAttributeName, attributeValue));
            doc.Root.Add(container);
        }
        else
        {
            // Remove old content.
            container.RemoveNodes();
        }

        var element = obj.SerializeToXElement();
        container.Add(element);
        return element;
    }

    public static T GetItem<T>(this XDocument doc, string attributeValue)
    {
        return doc.GetItem<T>(ContainerElementName, ContainerAttributeName, attributeValue);
    }

    static T GetItem<T>(this XDocument doc, XName containerElementName, XName containerAttributeName, string attributeValue)
    {
        if (doc == null || containerElementName == null || containerAttributeName == null || attributeValue == null)
            throw new ArgumentNullException();
        if (doc.Root == null)
            throw new ArgumentException("doc.Root == null");
        var container = doc.Root.Elements(containerElementName).Where(e => (string)e.Attribute(containerAttributeName) == attributeValue).SingleOrDefault();
        if (container == null)
            return default(T);
        var element = container.Elements().SingleOrDefault();
        if (element == null)
            return default(T);
        return element.Deserialize<T>();
    }

    public static XDocument CreateDefaultXDocument()
    {
        var xml = @"<StoredObjects></StoredObjects>";
        return XDocument.Parse(xml);
    }
}

现在可以了

doc.AddItem(MYOBJECT, objectName);

以后

var MYOBJECT2 = doc.GetItem<MYOBJECT_TYPE>(objectName);

示例 fiddle.

这篇关于在父元素内将对象序列化为 XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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