Сериализация WITHOUT xmlns
У меня есть несколько методов расширения, которые обрабатывают сериализацию моих классов, и поскольку это может быть трудоемкий процесс, они создаются один раз для каждого класса и передаются с помощью этого метода.
public static XmlSerializer GetSerializerFor(Type typeOfT)
{
if (!serializers.ContainsKey(typeOfT))
{
var xmlAttributes = new XmlAttributes();
var xmlAttributeOverrides = new XmlAttributeOverrides();
System.Diagnostics.Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));
xmlAttributes.Xmlns = false;
xmlAttributeOverrides.Add(typeOfT, xmlAttributes);
var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
serializers.Add(typeOfT, newSerializer);
}
return serializers[typeOfT];
}
Это вызывается методом расширения .Serialize()
public static XElement Serialize(this object source)
{
try
{
var serializer = XmlSerializerFactory.GetSerializerFor(source.GetType());
var xdoc = new XDocument();
using (var writer = xdoc.CreateWriter())
{
serializer.Serialize(writer, source, new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") }));
}
return (xdoc.Document != null) ? xdoc.Document.Root : new XElement("Error", "Document Missing");
}
catch (Exception x)
{
return new XElement("Error", x.ToString());
}
}
К сожалению, при сериализации классов, которые автоматически генерируются, у них есть атрибут XmlTypeAttribute(Namespace="http://tempuri.org/")
, примененный к ним.
Это приводит к сбою десериализации с помощью неавтомобильных копий.
Мне нужно, чтобы сериализатор полностью игнорировал и не применял пространство имен, но то, что я написал в первом блоке кода, похоже, не удаляет его, я все равно получаю xml, как этот
<Note>
<ID xmlns="http://tempuri.org/">12</ID>
<Author xmlns="http://tempuri.org/">
<ID>1234</ID>
<Type>Associate</Type>
<IsAvailable>false</IsAvailable>
</Author>
<Created xmlns="http://tempuri.org/">2010-06-22T09:38:01.5024351-05:00</Created>
<Text xmlns="http://tempuri.org/">This is an update</Text>
</Note>
Вместо того же, минус атрибут xmlns="http://tempuri.org/"
.
Пожалуйста, помогите, спасибо, это сводит меня с ума!
EDIT:
Я знаю проблему, а не как ее исправить.
Мой класс не просто заполнен простыми типами.
Он содержит свойства с типами других классов. Которые также автоматически генерируются с помощью атрибута XmlTypeAttribute(Namespace = "http://tempuri.org/")
. Итак, что происходит, заключается в том, что при сериализации происходит сериализация свойств моего класса, они не проходят мою собственную сериализацию и, таким образом, имеют атрибут, который применяется, а не переопределяется.
Теперь мне просто нужно выяснить, как прыгать в этом обруче. Любые мысли о том, как?
ИЗМЕНИТЬ 2:
Следующее работает, чтобы сериализовать WITHOUT xmlns... но у меня проблема с десериализационным концом, просто не уверен, связано это или нет.
public static XmlSerializer GetSerializerFor(Type typeOfT)
{
if (!serializers.ContainsKey(typeOfT))
{
var xmlAttributes = new XmlAttributes();
var xmlAttributeOverrides = new XmlAttributeOverrides();
System.Diagnostics.Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));
xmlAttributes.XmlType = new XmlTypeAttribute
{
Namespace = ""
};
xmlAttributes.Xmlns = false;
var types = new List<Type> {typeOfT, typeOfT.BaseType};
foreach (var property in typeOfT.GetProperties())
{
types.Add(property.PropertyType);
}
types.RemoveAll(t => t.ToString().StartsWith("System."));
foreach (var type in types)
{
xmlAttributeOverrides.Add(type, xmlAttributes);
}
var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
//var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, extraTypes.ToArray(), new XmlRootAttribute(), string.Empty);
//var newSerializer = new XmlSerializer(typeOfT, string.Empty);
serializers.Add(typeOfT, newSerializer);
}
return serializers[typeOfT];
}
EDIT3:
Закончилось использование решения из
Как удалить все пространства имен из XML с помощью С#?
public static XElement RemoveAllNamespaces(this XElement source)
{
return !source.HasElements
? new XElement(source.Name.LocalName)
{
Value = source.Value
}
: new XElement(source.Name.LocalName, source.Elements().Select(el => RemoveAllNamespaces(el)));
}
Ответы
Ответ 1
Нет проблем - просто передайте пустую строку в качестве пространства имен по умолчанию в XML-сериализатор:
XmlSerializer newSerializer =
new XmlSerializer(typeOfT, "");
К сожалению, нет никакой простой перегрузки конструктора, если вам действительно нужно определить XmlAttributeOverrides
и пространство имен по умолчанию - так что вы можете пропустить XmlAttributeOverrides
и использовать этот конструктор, о котором я упоминал, или вам нужно использовать тот, который определяет все возможные параметры (включая XmlAttributeOverrides и пространства имен XML по умолчанию - и еще несколько).
Ответ 2
Рабочее решение для записи!
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var serializer = new XmlSerializer(yourType);
serializer.Serialize(xmlTextWriter, someObject, ns);
Ответ 3
public static byte[] SerializeByteByType(object objectToSerialize, Type type)
{
XmlWriterSettings xmlSetting = new XmlWriterSettings()
{
NewLineOnAttributes = false,
OmitXmlDeclaration = true,
Indent = false,
NewLineHandling = NewLineHandling.None,
Encoding = Encoding.UTF8,
NamespaceHandling = NamespaceHandling.OmitDuplicates
};
using (MemoryStream stm = new MemoryStream())
{
using (XmlWriter writer = XmlWriter.Create(stm, xmlSetting))
{
var xmlAttributes = new XmlAttributes();
var xmlAttributeOverrides = new XmlAttributeOverrides();
xmlAttributes.Xmlns = false;
xmlAttributes.XmlType = new XmlTypeAttribute() { Namespace = "" };
xmlAttributeOverrides.Add(type, xmlAttributes);
XmlSerializer serializer = new XmlSerializer(type, xmlAttributeOverrides);
//Use the following to serialize without namespaces
XmlSerializerNamespaces xmlSrzNamespace = new XmlSerializerNamespaces();
xmlSrzNamespace.Add("", "");
serializer.Serialize(writer, objectToSerialize, xmlSrzNamespace);
stm.Flush();
stm.Position = 0;
}
return stm.ToArray();
}
}
Ответ 4
public static string SerializeToXml(object obj)
{
UTF8Encoding encoding = new UTF8Encoding(false);
var xmlAttributes = new XmlAttributes();
xmlAttributes.Xmlns = false;
xmlAttributes.XmlType = new XmlTypeAttribute() { Namespace = "" };
var xmlAttributeOverrides = new XmlAttributeOverrides();
var types = obj.GetType().Assembly.GetTypes().Where(t => string.Equals(t.Namespace, obj.GetType().Namespace, StringComparison.Ordinal));
foreach (var t in types) xmlAttributeOverrides.Add(t, xmlAttributes);
XmlSerializer sr = new XmlSerializer(obj.GetType(), xmlAttributeOverrides);
MemoryStream memoryStream = new MemoryStream();
StreamWriter writer = new StreamWriter(memoryStream, encoding);
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
// get the stream from the writer
memoryStream = writer.BaseStream as MemoryStream;
sr.Serialize(writer, obj, namespaces);
// apply encoding to the stream
return (encoding.GetString(memoryStream.ToArray()).Trim());
}
Это даже будет работать для сложного объекта, содержащего вложенный объект Кредиты для пользователя 3444796 и Mentor