2

我正在尝试在 C# 中序列化字典。我能够找到 所有示例都创建如下 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;
        }
    }
}

我注意到其他教程和我正在做的事情之间的一个区别是,许多人使用XmlSerializerand 中的对象进行序列化和反序列化ReadXmlWriteXml而我使用WriteElementStringand 之类的。

我的问题是,我怎样才能序列化一个字典,使它的 XML 就像我上面的第二个 XML 示例一样,但是序列化和反序列化 aList<MySerializableDictionary>也可以工作?即使只是暗示“你为什么要这样做这可能会让它变得有趣”也会有所帮助。

4

1 回答 1

2

WriteXml看起来还不错,因为它以我想要的 XML 格式输出字典的内容。 ReadXml是我出错的地方。基于本教程ReadXml中找到的实现,我想出了以下内容:

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在它是 an 时调用EndElement,并且还更改了外部while循环,以便读者可以Read()在它没有击中 anElement并且它没有击中 an EndElement(例如,它已经击中)时继续(通过Whitespace)。

于 2010-08-19T18:34:15.703 回答