patterncsharpMinor
Converting string array to string (and vice-versa) for storing via XML
Viewed 0 times
vicearrayversaxmlviaforandconvertingstoringstring
Problem
I'm using XML to store data and I need to store a string array in it. The best way (that I can think of) to store a string array is by converting it to a single string. In order to do that, I'm using
Retrieving String Array (Via XML)
Storing String Array (Via XML)
```
writer.WriteAttributeString("Name", this.Name);
writer.WriteAttributeString("Type", this.Type);
string strValue = string.Empty;
string[] val = (string[])this.Value;
List escapedStrs = new List();
foreach (string s in val)
{
string newStr = s;
// Escape backslashes so existing \\0 don't get mixed up
if (newStr.IndexOf('\\') > 0)
newStr = newStr.Replace("\\", "\\\\");
// If theres
string.Join to join the strings with \0 and then use Base64 so that the \0 (and any other special character) can be retrieved easier. Because it's possible that a string in a array already has \0 in it (causing another string to be the array when they're converted back to an array), I'm escaping the existing \0 by first adding another backslash to existing backslashes and changing \0 to \\0. Is there any better way to do this? Should I be using \r\n instead (but wouldn't that also be the same as using \0)? I should also note that its so I can use IXmlSerializable and it is also storing byte[], uint, ulong and string in the XML as well.Retrieving String Array (Via XML)
this.Name = reader.GetAttribute("Name");
string strType = reader.GetAttribute("Type");
byte[] buffer = new byte[1000];
int readBytes = 0;
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, 50)) > 0)
{
bw.Write(buffer, 0, readBytes);
}
bw.Close();
List unescapedStrs = new List();
string[] val = strValue.Split('\0');
string newStr;
foreach (string s in val)
{
newStr = Regex.Replace(s, @"([^\\])(\\0)", "$1\0").Replace("\\\\", "\\");
unescapedStrs.Add(newStr);
}
if (val.Length > 0)
this.Value = unescapedStrs.ToArray();Storing String Array (Via XML)
```
writer.WriteAttributeString("Name", this.Name);
writer.WriteAttributeString("Type", this.Type);
string strValue = string.Empty;
string[] val = (string[])this.Value;
List escapedStrs = new List();
foreach (string s in val)
{
string newStr = s;
// Escape backslashes so existing \\0 don't get mixed up
if (newStr.IndexOf('\\') > 0)
newStr = newStr.Replace("\\", "\\\\");
// If theres
Solution
My first reaction is: don't do this.
By creating your own encoding for an array of strings, your XML is not going to be (easily) consumable by other programs. By Base64 encoding your strings, your XML is not going to be human-readable.
These are two major benefits of XML, and if you're willing to sacrifice them, maybe XML is not the right format. If the serialized data is only going to be consumed by the same program, binary serialization would be a better option.
That said, if you want to serialize a list of strings to XML, this is what I would recommend:
And some sample client code:
This will output
Now, this chokes if the strings contain a null-byte, which you mentioned was a possibility. It's hard to say what to do about this without knowing more about your problem domain. Hopefully, stripping null-bytes is an option for you.
Serializing a
By creating your own encoding for an array of strings, your XML is not going to be (easily) consumable by other programs. By Base64 encoding your strings, your XML is not going to be human-readable.
These are two major benefits of XML, and if you're willing to sacrifice them, maybe XML is not the right format. If the serialized data is only going to be consumed by the same program, binary serialization would be a better option.
That said, if you want to serialize a list of strings to XML, this is what I would recommend:
public class Email
{
private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(Email));
[XmlArrayItem("Attachment")]
public List Attachments { get; set; }
public XDocument ToXDocument()
{
var document = new XDocument();
using (var writer = document.CreateWriter())
{
Serializer.Serialize(writer, this);
}
return document;
}
}And some sample client code:
var email = new Email
{
Attachments = new List { "", "asdf" }
};
var xml = email.ToXDocument().ToString();
Console.WriteLine(xml);This will output
<hello></hello>
asdf
Now, this chokes if the strings contain a null-byte, which you mentioned was a possibility. It's hard to say what to do about this without knowing more about your problem domain. Hopefully, stripping null-bytes is an option for you.
Serializing a
byte[] as a Base64-encoded string can be done using a surrogate property:[XmlIgnore]
public byte[] Bytes { get; set; }
public string BytesBase64
{
get { return Convert.ToBase64String(this.Bytes); }
set { this.Bytes = Convert.FromBase64String(value); }
}Code Snippets
public class Email
{
private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(Email));
[XmlArrayItem("Attachment")]
public List<string> Attachments { get; set; }
public XDocument ToXDocument()
{
var document = new XDocument();
using (var writer = document.CreateWriter())
{
Serializer.Serialize(writer, this);
}
return document;
}
}var email = new Email
{
Attachments = new List<string> { "<hello></hello>", "asdf" }
};
var xml = email.ToXDocument().ToString();
Console.WriteLine(xml);<Email xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Attachments>
<Attachment><hello></hello></Attachment>
<Attachment>asdf</Attachment>
</Attachments>
</Email>[XmlIgnore]
public byte[] Bytes { get; set; }
public string BytesBase64
{
get { return Convert.ToBase64String(this.Bytes); }
set { this.Bytes = Convert.FromBase64String(value); }
}Context
StackExchange Code Review Q#57116, answer score: 2
Revisions (0)
No revisions yet.