c# - C# 中的 IXmlSerialized 字典没有 'Key'/'Value' 节点

标签 c# dictionary xml-serialization serialization ixmlserializable

我正在尝试用 C# 序列化字典。全部the examples我已经能够找到如下所示的创建 XML:

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

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

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

我写了ReadXmlWriteXml之前执行此操作并且它适用于单个字典,但是如果我尝试序列化和反序列化 List<T>在我的可序列化字典实例中,反序列化列表最终仅包含最后可序列化字典。我认为我的读取或写入方法一定是贪婪的,以至于它不知道何时停止。以下是我的可序列化字典方法,目前不适用于 List 的序列化可序列化字典的:

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等等。

我的问题是,如何序列化字典,使其 XML 就像上面的第二个 XML 示例一样,但序列化和反序列化 List<MySerializableDictionary>也有效吗?即使只是暗示“你为什么要这么做,这可能会让事情变得有趣”也会有所帮助。

最佳答案

我的WriteXml看起来不错,因为它以我想要的 XML 格式输出字典的内容。 ReadXml是我出错的地方。基于ReadXml发现实现in this tutorial ,我想出了以下内容:

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 添加任何特殊处理,我确信这是必要的。不过,这似乎是一个开始。

编辑:实际上,也许我只需要在编写时担心CDATA,而不是在阅读时担心。

编辑:更新ReadXml上面的代码说明 XmlNodeType.Whitespace ,当您反序列化时可以在 XML 文件中找到它。我收到 XML 错误,因为 ReadEndElementreader.NodeType 被调用时不是XmlNodeType.EndElement 。对此进行检查,以便它只调用 ReadEndElement当它是EndElement时,并且还改变了外部while循环,以便读者在未达到 Read() 时可以继续前进(通过 Element )而且还没有达到 EndElement (例如,它已命中 Whitespace )。

关于c# - C# 中的 IXmlSerialized 字典没有 'Key'/'Value' 节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3523503/

相关文章:

c# - SqlDataAdapter 不删除记录

python - 在 Python 中计算字典中不同键的数量

java - 如何以内存高效的方式将 xml 写入 bean 网络流

c# - Xmlserializer 不序列化基类成员

c# - c# 中的派生用户控件会覆盖其父级的 html 是否可以不这样做?

c# - winRT拖放,交换两个项目而不是插入

c# - C# 中的图像转换

python - 以更有吸引力的方式打印字典键

Python:具有相同键的几个字典的平均值

c# - 简单的 C# Xml 序列化