Як серіалізувати об’єкт у 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лайно?
розчавити

Зверніться до відповіді stackoverflow.com/questions/31946240/… , якщо q1 додано до порожнього простору імен
aniruddha

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
        }
    }

Остерігайтеся, 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.'
Тайлер StandishMan

Щоб обійти це і продовжувати використовувати XmlReader, ви можете використовувати var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);Істинний буде використовувати BOM, якщо він знайдеться, інакше вказаний вами за замовчуванням.
Tyler StandishMan

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
}

:)


чудова відповідь :) Я також додав цей потік рядків.Position = 0; і повернув весь потік в моєму рішенні .. працював як слід - всі теги уповільнення видалено
ymz

Додавання аргументу просторів імен до виклику серіалізатора працювало мені для видалення просторів імен за замовчуванням. Написання new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})замість new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})- це, на мою думку, навмисне зрозуміліший спосіб кодування.
Suncat2000

5

Якщо ви не можете позбутися зайвих атрибутів xmlns для кожного елемента, під час серіалізації до xml з генерованих класів (наприклад, коли xsd.exe використовувався), то у вас є щось на кшталт:

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

то я б поділився з вами тим, що працювало на мене (суміш попередніх відповідей і що я тут знайшов )

явно встановіть усі ваші різні xmlns наступним чином:

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();
        }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.