开发者

XmlSerializer and embedded WhiteSpace

I have the following xml that contains a white space Field1Value . When I deserialize that xml I lose the single space character. The value of Request.Field2 is "". Is this a bug in the xml serializer? Can anyone recommend a solution/ workaround to keep this space?

  ...
            var encoding = new System.Text.UTF8Encoding();
            var _xmlData = "<Request><Field1>Field1Value</Field1><Field2>   </Field2></Request>";
            var _xmlDataAsByteArray = new byte[_xmlData.Length];
            _xmlDataAsByteArray = encoding.GetBytes(_xmlData);

            var _memoryStream = new MemoryStream(_xmlDataAsByteArray);

           var _XmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Request));

            Request _request = _XmlSerializer.Deserialize(_memoryStream) as Request;

  ...
         public class Request
           {
               public string Field1;
               public s开发者_如何学Gotring Field2;
           }


No, this is not a bug, but expected behavior. Unless you opt-in for preserving space, XML is processors (i.e. the apps reading and writing XML) are supposed to normalize whitespace. See section 2.1 of the XML 1.1 specification here.

To preserve the whitespace you have to include the xml:space="preserve" attribute. Hence the XML shall look like this:

<Request>
   <Field1>Field1Value</Field1>
   <!-- spaces inside Field2 will be preserved -->
   <Field2 xml:space="preserve">   </Field2> 
</Request>


You can use the XmlReader to load the xml with IngoreWhitespace set to false

new XmlSerializer(typeof(Request)).Deserialize(XmlReader.Create(_memoryStream, new XmlReaderSettings { IgnoreWhitespace = false })) as Request;


Maybe the xml:space attribute can help by setting it to 'preserve'. See this article as a starting point.


I was just looking into dealing with preserving whitespace and this answer is useful in that regard: How do I preserve whitespace characters when parsing XML from C# LINQ


I just encountered this problem. In my case the XML is generated by code I control so I was able to add the xml:space=preserve attribute. I was using IXmlSerializable (for a good reason that I won't go in to here). Here's how I did it, in case this is helpful to someone (it's hard to find examples of much of this Xml serialization/deserialization). This WriteSettings() method is called by my WriteXml() method implementing IXmlSerializable.

    public static void WriteSettings(XmlWriter writer, Dictionary<string, string> settings)
    {
        foreach (string key in settings.Keys)
        {
            string value = settings[key];
            writer.WriteStartElement("Setting");
            writer.WriteElementString("SettingType", key);

            //writer.WriteElementString("SettingValue", value);
            // I replaced the above line, which I had previously, 
            // with the below 5 lines. 
            writer.WriteStartElement("SettingValue");
            if (value != value.Trim())
                writer.WriteAttributeString("xml", "space", null, "preserve");
            writer.WriteString(value);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }

This gives me XML that looks like this (enclosing element written by enclosing object, not the WriteSettings method above):

<ResourceSettings>
  <Setting>
    <SettingType>SomeSettingName</SettingType>
    <SettingValue>1</SettingValue>
  </Setting>
  <Setting>
    <SettingType>AnotherSettingName</SettingType>
    <SettingValue xml:space="preserve"> </SettingValue>
  </Setting>
  <Setting>
    <SettingType>ADifferentSettingName</SettingType>
    <SettingValue>some other value</SettingValue>
  </Setting>
</ResourceSettings>

I read this in using the same code I had before and the XmlReader respects the xml:space=preserve attribute, e.g.:

    public void ReadXml(XmlReader reader)
    {
        _cache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
        if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "ResourceSettings")
        {
            // Deal with the case where there are no settings
            if (reader.ReadToDescendant("Setting"))
            {
                while (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "Setting")
                {
                    reader.ReadStartElement("Setting");
                    string key = reader.ReadElementString("SettingType");
                    string value = reader.ReadElementString("SettingValue");
                    reader.ReadEndElement();
                    _cache.Add(key, value);
                }
            }
            reader.Read(); // move past container
        }
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜