【问题标题】:Serialize object to XML WITHIN a parent element在父元素内将对象序列化为 XML
【发布时间】:2016-09-23 10:15:33
【问题描述】:

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

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 a parent 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);
    }
}

编辑:

目前,这就是我所拥有的(但它会引发异常 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);
}

【问题讨论】:

  • 1) 什么是shape?在shape.CreateWriter(); 行中,它是未定义的。 2) 可以分享CreateDefaultXml();吗?
  • @dbc 对不起。我已经更新了问题
  • 我将MessageBox.Show 改为显示ex.InnerException 并得到System.InvalidOperationException: WriteStartDocument cannot be called on writers created with ConformanceLevel.Fragment.

标签: c# xml wpf serialization


【解决方案1】:

您正在尝试使用XmlSerializer 直接序列化到XDocument 内的一些嵌套XElement。不幸的是,当使用XmlSerializerXContainer.CreateWriter() 直接序列化为LINQ-to-XML XElement 时,实际上需要序列化为空的XDocument,从而创建其根元素。 (我不知道为什么存在这个限制,但确实存在。)由于这不能满足您的需求,因此很容易序列化为 temporary XDocument,删除其根节点,然后添加该节点到您的整个元素层次结构。

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

我将您的代码重构为扩展方法来完成此操作:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    相关资源
    最近更新 更多