Как сериализовать объект в XML без получения xmlns = «…»?

109

Есть ли способ сериализации объекта в .NET без автоматической сериализации пространств имен XML? Кажется, что по умолчанию .NET считает, что пространства имен XSI и XSD должны быть включены, но я не хочу, чтобы они там были.

Уэс П
источник

Ответы:

142

Ах ... да ладно. Всегда поиск после того, как вопрос поставлен, дает ответ. Мой объект, который сериализуется obj, уже определен. Добавление XMLSerializerNamespace с одним пустым пространством имен в коллекцию делает свое дело.

В VB так:

Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
Dim ns As New XmlSerializerNamespaces()
ns.Add("", "")

Dim settings As New XmlWriterSettings()
settings.OmitXmlDeclaration = True

Using ms As New MemoryStream(), _
    sw As XmlWriter = XmlWriter.Create(ms, settings), _
    sr As New StreamReader(ms)
xs.Serialize(sw, obj, ns)
ms.Position = 0
Console.WriteLine(sr.ReadToEnd())
End Using

в C # вот так:

//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

//Add an empty namespace and empty value
ns.Add("", "");

//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);

//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns);
Уэс П
источник
12
Я пробовал это в VB, атрибуты xsi и xsd исчезли, но появились такие атрибуты, как xmlns: q12 =, d3p1: type и xmlns: d3p1.
MiddleKay
16
Я попробовал версию C #, и она удалила xsi и xsd, но добавила префикс q1: ко всем именам тегов XML, которые мне не нужны. Похоже, что пример C # неполный, ссылаясь на myXmlTextWriter, который, как я полагаю, должен быть инициализирован так же, как пример VB.
redtetrahedron
1
@redtetrahedron Вы нашли способ избавиться от q1дерьма?
Crush
Обратитесь к ответу stackoverflow.com/questions/31946240/… , если q1 добавлен как пустое пространство имен
анируддха
20

Если вы хотите избавиться от лишнего xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"и xmlns:xsd="http://www.w3.org/2001/XMLSchema", но при этом сохранить собственное пространство имен xmlns="http://schemas.YourCompany.com/YourSchema/", используйте тот же код, что и выше, за исключением этого простого изменения:

//  Add lib namespace with empty prefix  
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   
Али Б
источник
13

Если вы хотите удалить пространство имен, вы также можете удалить версию, чтобы сэкономить на поиске, я добавил эту функцию, поэтому приведенный ниже код будет делать и то, и другое.

Я также обернул его в универсальный метод, поскольку я создаю очень большие XML-файлы, которые слишком велики для сериализации в памяти, поэтому я разбил свой выходной файл и сериализовал его на более мелкие «куски»:

    public static string XmlSerialize<T>(T entity) where T : class
    {
        // removes version
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;

        XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
        using (StringWriter sw = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(sw, settings))
        {
            // removes namespace
            var xmlns = new XmlSerializerNamespaces();
            xmlns.Add(string.Empty, string.Empty);

            xsSubmit.Serialize(writer, entity, xmlns);
            return sw.ToString(); // Your XML
        }
    }
D34th
источник
Осторожно, по StringWriterумолчанию используется кодировка UTF-16, что может привести к проблемам с десериализацией в дальнейшем. using (var reader = XmlReader.Create(stream)){ reader.Read(); }Это вызывает исключение, потому что в объявлении указано, что это UTF-16, в то время как содержимое фактически было записано как UTF-8. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Тайлер Стэндишман,
Чтобы обойти это и по-прежнему использовать XmlReader, вы можете использовать var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);True будет использовать спецификацию, если она найдена, иначе значение по умолчанию, которое вы предоставите.
Тайлер Стэндишман,
9

Предлагаю этот вспомогательный класс:

public static class Xml
{
    #region Fields

    private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
    private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});

    #endregion

    #region Methods

    public static string Serialize(object obj)
    {
        if (obj == null)
        {
            return null;
        }

        return DoSerialize(obj);
    }

    private static string DoSerialize(object obj)
    {
        using (var ms = new MemoryStream())
        using (var writer = XmlWriter.Create(ms, WriterSettings))
        {
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj, Namespaces);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public static T Deserialize<T>(string data)
        where T : class
    {
        if (string.IsNullOrEmpty(data))
        {
            return null;
        }

        return DoDeserialize<T>(data);
    }

    private static T DoDeserialize<T>(string data) where T : class
    {
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
        {
            var serializer = new XmlSerializer(typeof (T));
            return (T) serializer.Deserialize(ms);
        }
    }

    #endregion
}

:)

Мазиар Тахери
источник
отличный ответ :) Я также добавил эту строку stream.Position = 0; и вернул весь поток в моем решении .. работал, как ожидалось - все теги замедления были удалены
ymz
Добавление аргумента namespaces к вызову сериализатора помогло мне удалить пространства имен по умолчанию. На мой взгляд, написание new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})вместо new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})- это намеренно более четкий способ кодирования.
Suncat2000
5

Если вы не можете избавиться от лишних атрибутов xmlns для каждого элемента при сериализации в xml из сгенерированных классов (например, когда использовался xsd.exe ), у вас есть что-то вроде:

<manyElementWith xmlns="urn:names:specification:schema:xsd:one" />

тогда я бы поделился с вами, что сработало для меня (смесь предыдущих ответов и того, что я нашел здесь )

явно установите все ваши XML-файлы следующим образом:

Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add("one", "urn:names:specification:schema:xsd:one")
xmlns.Add("two",  "urn:names:specification:schema:xsd:two")
xmlns.Add("three",  "urn:names:specification:schema:xsd:three")

затем передайте его в сериализацию

serializer.Serialize(writer, object, xmlns);

у вас будет три пространства имен, объявленных в корневом элементе, и больше не нужно будет создавать в других элементах, которые будут иметь соответствующий префикс

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...
Виньензо
источник
0
        XmlWriterSettings settings = new XmlWriterSettings
        {
            OmitXmlDeclaration = true
        };

        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");

        StringBuilder sb = new StringBuilder();

        XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));

        using (XmlWriter xw = XmlWriter.Create(sb, settings))
        {
            xs.Serialize(xw, model, ns);
            xw.Flush();
            return sb.ToString();
        }
Телец
источник