XML (de) сериализация неверная строка несовместима в С#?
В С# (.net 4.0 и 4.5/vs2010 и vs12), когда я сериализую объект, содержащий строку с недопустимым символом, используя XMLSerializer, не возникает ошибка. Однако, когда я десериализую этот результат, выдается ошибка "недопустимый символ".
// add to XML
Items items = new Items();
items.Item = "\v hello world"; // contains "illegal" character \v
// variables
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Items));
string tmpFile = Path.GetTempFileName();
// serialize
using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.Open, FileAccess.ReadWrite))
{
serializer.Serialize(tmpFileStream, items);
}
Console.WriteLine("Success! XML serialized in file " + tmpFile);
// deserialize
Items result = null;
using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
{
result = (Items)serializer.Deserialize(plainTextFile); //FAILS here
}
Console.WriteLine(result.Item);
"Элементы" - это всего лишь небольшой класс, автогенерируемый xsd/c Items.xsd. Items.xsd - не что иное, как корневой элемент (Items), содержащий один дочерний элемент (Item):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Items">
<xs:complexType>
<xs:sequence>
<xs:element name="Item" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Ошибка, возникающая при десериализации,
Необработанное исключение: System.InvalidOperationException: существует ошибка в документе XML (3, 12). --- > System.Xml.XmlException: '♂', шестнадцатеричное значение 0x0B, является недопустимым символом. Строка 3, позиция 12.
Сериализованный XML файл содержит в строке 3 следующее:
<Item> hello world</Item>
Я знаю \v → и # xB; является незаконным символом, но почему XMLSerialize позволяет сериализовать (без ошибок)? Я считаю, что это несовместимо с .NET, что позволяет мне сериализовать что-то без проблем, только чтобы узнать, что я не могу десериализировать его.
Есть ли решение, чтобы либо XMLSerializer автоматически удалял незаконные символы перед сериализацией, либо я могу дать указание десериализации игнорировать недопустимые символы?
В настоящее время я решаю его, читая содержимое файла в виде строки, заменяя "вручную" незаконные символы и следующий десериализуя его... но я нахожу, что уродливый хак/работа вокруг.
Ответы
Ответ 1
1.
Вы можете установить свойство XmlWriterSettings
CheckCharacters
, чтобы избежать написания незаконных символов. (Serialize
метод выбрал бы исключение)
using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
var writer = XmlWriter.Create(tmpFileStream, new XmlWriterSettings() { CheckCharacters = true});
serializer.Serialize(writer, items);
}
2.
Вы можете создать свой собственный XmlTextWriter для фильтрации нежелательных символов при сериализации
using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
var writer = new MyXmlWriter(tmpFileStream);
serializer.Serialize(writer, items);
}
public class MyXmlWriter : XmlTextWriter
{
public MyXmlWriter(Stream s) : base(s, Encoding.UTF8)
{
}
public override void WriteString(string text)
{
string newText = String.Join("", text.Where(c => !char.IsControl(c)));
base.WriteString(newText);
}
}
3.
Создав собственный XmlTextReader, вы можете отфильтровывать нежелательные символы при десериализации
using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
{
var reader = new MyXmlReader(plainTextFile);
result = (SomeObject)serializer.Deserialize(reader);
}
public class MyXmlReader : XmlTextReader
{
public MyXmlReader(Stream s) : base(s)
{
}
public override string ReadString()
{
string text = base.ReadString();
string newText = String.Join("", text.Where(c => !char.IsControl(c)));
return newText;
}
}
4.
Вы можете установить для свойства XmlReaderSettings
CheckCharacters
значение false. Дезириализация будет работать гладко. (вы получите \v
назад.)
using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
{
var reader = XmlReader.Create(plainTextFile, new XmlReaderSettings() { CheckCharacters = false });
result = (SomeObject)serializer.Deserialize(reader);
}