词典<;字符串,字符串>;序列化:在ReadXml()之后,将跳过后续的XML元素

本文关键字:字符串 XML 元素 之后 ReadXml 序列化 gt lt 词典 | 更新日期: 2023-09-27 18:27:35

在我的一个对象中,我有一个字典,它是通过实现IXmlSerializable:来序列化的

    public SerializableStringDictionary Parameters { get; set; }

当我用普通的.NET序列化程序序列化这些对象的列表时,它会很好地序列化,但是反序列化只做单个对象——XML文件中遵循可序列化字典的元素会被跳过。

例如,我有一个<MaintenanceIndicators>的列表。我在下面只显示了一个,但这是代码中的List<MaintenanceIndicator>。具有多个条目的列表的序列化工作正常,但反序列化多个条目只会在列表中提供1个MaintenanceIndicator。但是,它的parameters属性反序列化正常。代码中没有引发异常。

我使用以下代码进行反序列化:

    public void ReadXml(XmlReader reader)
    {
        bool wasEmpty = reader.IsEmptyElement;
        // jump to <parameters>
        reader.Read();
        if (wasEmpty)
            return;
        // read until we reach the last element
        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            // jump to <item>
            reader.MoveToContent();
            // jump to key attribute and read
            reader.MoveToAttribute("key");
            string key = reader.GetAttribute("key");
            // jump to value attribute and read
            reader.MoveToAttribute("value");
            string value = reader.GetAttribute("value");
            // add item to the dictionary
            this.Add(key, value);
            // jump to next <item>
            reader.ReadStartElement("item");
            reader.MoveToContent(); // workaround to trigger node type
        }
    }

我的XML结构如下:

<MaintenanceIndicators>
<MaintenanceIndicator Id="1" Name="Test" Description="Test" Type="LimitMonitor" ExecutionOrder="1">
  <Parameters>
    <item key="Input" value="a" />
    <item key="Output" value="b" />
    <item key="Direction" value="GreaterThan" />
    <item key="LimitValue" value="1" />
    <item key="Hysteresis" value="1" />
  </Parameters>
</MaintenanceIndicator>
 <!-- Any subsequent MaintenanceIndicator indicator element will not be read -->
</MaintenanceIndicators>

词典<;字符串,字符串>;序列化:在ReadXml()之后,将跳过后续的XML元素

您的问题没有包含问题的完整示例。为了确认,您有以下(简化的)类定义,SerializableStringDictionary如您的问题所示:

public class MaintenanceIndicator
{
    public MaintenanceIndicator()
    {
        this.Parameters = new SerializableStringDictionary();
    }
    public SerializableStringDictionary Parameters { get; set; }
}
[XmlRoot("MaintenanceIndicators")]
public class MaintenanceIndicators
{
    [XmlElement("MaintenanceIndicator")]
    public List<MaintenanceIndicator> MaintenanceIndicatorList { get; set; }
}

以及以下XML:

<MaintenanceIndicators>
  <MaintenanceIndicator>
    <Parameters>
      <item key="Input" value="a" />
      <item key="Output" value="b" />
    </Parameters>
  </MaintenanceIndicator>
  <MaintenanceIndicator>
    <Parameters>
      <item key="Input2" value="a" />
      <item key="Output2" value="b" />
    </Parameters>
  </MaintenanceIndicator>
</MaintenanceIndicators>

在这种情况下,使用您的ReadXml(),我能够重现,在阅读上面的解析时,只有第一个<MaintenanceIndicator>元素被反序列化。

您的问题是,在ReadXml()中,您没有使用</Parameters>端节点。来自文档:

当这个方法返回时,它必须从头到尾读取整个元素,包括它的所有内容。与WriteXml方法不同,该框架不会自动处理包装器元素。您的实现必须这样做。不遵守这些定位规则可能会导致代码生成意外的运行时异常或损坏数据。

如果不能在ReadXml()的末尾调用reader.Read();来读取元素末尾,将导致XML中所有后续元素被跳过或以其他方式被错误读取。

因此,您应该修改ReadXml()如下:

    public void ReadXml(XmlReader reader)
    {
        bool wasEmpty = reader.IsEmptyElement;
        // jump to <parameters>
        reader.Read();
        if (wasEmpty)
            return;
        // read until we reach the last element
        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            // jump to <item>
            reader.MoveToContent();
            // jump to key attribute and read
            string key = reader.GetAttribute("key");
            // jump to value attribute and read
            string value = reader.GetAttribute("value");
            // add item to the dictionary
            this.Add(key, value);
            // jump to next <item>
            reader.ReadStartElement("item");
            reader.MoveToContent(); // workaround to trigger node type
        }
        // Consume the </Parameters> node as required by the documentation
        // https://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.readxml%28v=vs.110%29.aspx
        // Unlike the WriteXml method, the framework does not handle the wrapper element automatically. Your implementation must do so. 
        reader.Read();
    }

请注意,在调用reader.GetAttribute(string name)之前不需要调用reader.MoveToAttribute(string name)

如果您需要处理低类型对象(如字典所示),使用javascript序列化程序而不是XML会更加灵活。

例如:

    private void button1_Click(object sender, EventArgs e)
    {
        List<Dictionary<string, string>> datas = new List<Dictionary<string, string>>();
        Dictionary<string,string> d1 = new Dictionary<string,string> ();
        d1.Add ( "key11","value11");
        d1.Add ( "key12","value12");
        Dictionary<string,string> d2 = new Dictionary<string,string> ();
        d2.Add ( "key21","value21");
        d2.Add ( "key22","value22");
        datas.Add(d1);
        datas.Add(d2);
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        string serialized = serializer.Serialize (datas);
        List<Dictionary<string, string>> deserialized = serializer.Deserialize<List<Dictionary<string, string>>>(serialized);
    }

让我知道这种序列化在您的场景

中是否可以接受