C#中没有“键"/“值"节点的IXmlSerializable字典 [英] IXmlSerializable dictionary in C# without 'Key'/'Value' nodes

查看:54
本文介绍了C#中没有“键"/“值"节点的IXmlSerializable字典的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试序列化C#中的字典.所有 the

I'm trying to serialize a dictionary in C#. All the examples I've been able to find create XML like the following:

<Dictionary>
    <ArrayOfEntries>
        <Entry>
            <Key>myFirstKey</Key>
            <Value>myFirstValue</Value>
        </Entry>
        <Entry>
            <Key>mySecondKey</Key>
            <Value>mySecondValue</Value>
        </Entry>
    </ArrayOfEntries>
</Dictionary>

情况有所不同,有时不需要 ArrayOfEntries 节点,但是我仍然看到字典的键/值对的常规模式存储在它们自己的节点中.我想要的是以下内容:

It varies, sometimes the ArrayOfEntries node isn't necessary, but I still see the regular pattern of the dictionary's key-value pairs being stored in their own nodes. What I would like is something like the following:

<Dictionary>
    <myFirstKey>myFirstValue</myFirstKey>
    <mySecondKey>mySecondValue</mySecondKey>
</Dictionary>

我之前已经写过 ReadXml WriteXml 来做到这一点,并且它适用于单个字典,但是如果我尝试序列化和反序列化 List< T> (可序列化的字典实例),反序列化列表最后只包含 last 可序列化的字典.我认为必须对我的读取或写入方法感到有些贪婪,以至于它不知道何时停止.这是我的可序列化字典方法,目前不适用于可序列化字典的 List 的序列化:

I have written ReadXml and WriteXml to do this before and it works for a single dictionary, but if I try to serialize and deserialize a List<T> of my serializable dictionary instances, the deserialized list ends up with only the last serializable dictionary in it. I think something must be greedy about my read or write method such that it doesn't know when to stop. Here are my serializable dictionary methods that currently don't work for serialization of List's of serializable dictionaries:

public void WriteXml(XmlWriter writer)
{
    foreach (string key in getKeysToSerialize())
    {
        string cleanKey = key.SanitizeForXml();
        string value = getValueForKey(key).Trim();

        if (isCdata(key, value))
        {
            string cdataFriendlyValue = cleanStringForUseInCdata(value);
            if (string.IsNullOrEmpty(cdataFriendlyValue))
            {
                continue;
            }

            writer.WriteStartElement(cleanKey);
            writer.WriteCData(cdataFriendlyValue);
            writer.WriteEndElement();
        }
        else
        {
            writer.WriteElementString(cleanKey, value);
        }
    }
}

ReadXml :

public void ReadXml(XmlReader reader)
{
    string key = null, value = null;
    bool wasEmpty = reader.IsEmptyElement;

    while (reader.Read())
    {
        if (wasEmpty)
        {
            return;
        }

        switch (reader.NodeType)
        {
            case XmlNodeType.Element:
                key = reader.Name;
                if (keyIsSubTree(key))
                {
                    using (XmlReader subReader = reader.ReadSubtree())
                    {
                        storeSubtree(key, subReader);
                    }

                    // Reset key to null so we don't try to parse it as
                    // a regular key-value pair later
                    key = null;
                }
                break;
            case XmlNodeType.Text:
                value = reader.Value;
                break;
            case XmlNodeType.CDATA:
                value = cleanCdataForStoring(reader.Value);
                break;
            case XmlNodeType.EndElement:
                if (!string.IsNullOrEmpty(key))
                {
                    string valueToStore =
                        string.IsNullOrEmpty(value) ? string.Empty : value
                    Add(key, valueToStore);
                }
                key = null;
                value = null;
                break;
        }
    }
}

我在其他教程之间注意到的一个区别是,许多教程都使用 XmlSerializer ReadXml WriteXml中的对象进行序列化和反序列化,而我使用 WriteElementString 等.

One difference I've noticed between other tutorials and what I'm doing is that many use XmlSerializer to serialize and deserialize objects in their ReadXml and WriteXml, whereas I use WriteElementString and the like.

我的问题是,我怎样才能序列化一个字典,使它的XML像上面的第二个XML示例一样,但是序列化和反序列化 List< MySerializableDictionary> 的方法也可以工作?甚至只是暗示您为什么要做等等,这可能会使它表现得很有趣".

My question is, how can I serialize a dictionary such that its XML is like my second XML example above, but so that serializing and deserializing a List<MySerializableDictionary> also works? Even just hints of "why are you doing blah, that might make it act funny" would help.

推荐答案

我的 WriteXml 似乎还可以,因为它以我想要的XML格式输出字典的内容. ReadXml 是我出问题的地方.基于 ReadXml 实现,在本教程中 ,我提出了以下建议:

My WriteXml seemed okay because it outputs the dictionary's content in the XML format I want. ReadXml was where I was going wrong. Based on the ReadXml implementation found in this tutorial, I came up with the following:

public override void ReadXml(XmlReader reader)
{
    reader.MoveToContent();
    bool isEmptyElement = reader.IsEmptyElement;
    reader.ReadStartElement();
    if (isEmptyElement)
    {
        return;
    }
    while (XmlNodeType.EndElement != reader.NodeType)
    {
        // Bypass XmlNodeType.Whitespace, as found in XML files
        while (XmlNodeType.Element != reader.NodeType)
        {
            if (XmlNodeType.EndElement == reader.NodeType)
            {
                reader.ReadEndElement();
                return;
            }
            reader.Read();
        }
        string key = reader.Name;
        if (keyIsSubTree(key))
        {
            storeSubtree(key, reader.ReadSubtree());
        }
        else
        {
            string value = reader.ReadElementString();
            storeKeyValuePair(key, value ?? string.Empty);
        }
    }
    if (XmlNodeType.EndElement == reader.NodeType)
    {
        reader.ReadEndElement();
    }
}

这似乎适用于只有一个键值对的字典以及具有多个键值对的字典.我对字典的 List< T> 进行序列化/反序列化的测试也有效.我还没有为CDATA添加任何特殊处理,并且我相信这是必要的.不过,这似乎只是一个开始.

This seemed to work for dictionaries that had only one key-value pair as well as dictionaries with multiple key-value pairs. My test of serializing/deserializing a List<T> of dictionaries also worked. I haven't added any special handling for CDATA yet, and I'm sure that will be necessary. This seems like a start, though.

实际上,也许我只需要在写作时担心CDATA,而在阅读时就不必担心.

actually, maybe I only need to worry about CDATA when I'm writing, not when reading.

编辑:更新了上面的 ReadXml 代码,以说明 XmlNodeType.Whitespace ,在反序列化时会在XML文件中找到该代码.我收到XML错误是因为 reader.NodeType 不是 XmlNodeType.EndElement 时调用了 ReadEndElement .进行检查,以使其仅在 EndElement 时调用 ReadEndElement ,并且还更改了外部 while 循环,以便读者可以继续前进(通过 Read()),当它没有命中 Element 并且没有命中 EndElement 时(例如,它命中了空格).

updated ReadXml code above to account for XmlNodeType.Whitespace, which is found in XML files when you're deserializing. I was getting an XML error because ReadEndElement was being called when the reader.NodeType was not an XmlNodeType.EndElement. Put in a check for that so it only calls ReadEndElement when it's an EndElement, and also changed the outer while loop so the reader can progress (via Read()) when it hasn't hit an Element and it hasn't hit an EndElement (e.g., it has hit Whitespace).

这篇关于C#中没有“键"/“值"节点的IXmlSerializable字典的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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