Bagaimana cara membuat serial objek ke XML tanpa mendapatkan xmlns = “…”?

109

Apakah ada cara bagi saya untuk membuat serial objek di .NET tanpa XML Namespaces secara otomatis juga membuat serial? Tampaknya secara default. NET percaya ruang nama XSI dan XSD harus disertakan, tetapi saya tidak ingin mereka ada di sana.

Wes P
sumber

Jawaban:

142

Ahh ... lupakan. Itu selalu pencarian setelah pertanyaan diajukan yang menghasilkan jawabannya. Objek saya yang sedang diserialisasi adalah objdan telah ditentukan. Menambahkan XMLSerializerNamespace dengan satu namespace kosong ke koleksi akan berhasil.

Di VB seperti ini:

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

di C # seperti ini:

//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);
Wes P
sumber
12
Saya mencoba ini di VB, atribut xsi dan xsd menghilang tetapi atribut seperti xmlns: q12 =, d3p1: type, dan xmlns: d3p1 muncul.
MiddleKay
16
Saya mencoba versi C # dan menghapus xsi dan xsd tetapi menambahkan awalan q1: ke semua nama tag XML, yang tidak saya inginkan. Sepertinya contoh C # tidak lengkap, merujuk myXmlTextWriter yang saya asumsikan perlu diinisialisasi dengan cara yang sama seperti contoh VB.
redtetrahedron
1
@redtetrahedron Apakah Anda menemukan cara untuk menyingkirkan q1omong kosong itu?
hancurkan
Lihat jawaban stackoverflow.com/questions/31946240/… , jika q1 ditambahkan sebagai namespace kosong
aniruddha
20

Jika Anda ingin membuang ekstra xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"dan xmlns:xsd="http://www.w3.org/2001/XMLSchema", tetapi tetap mempertahankan namespace Anda sendiri xmlns="http://schemas.YourCompany.com/YourSchema/", Anda menggunakan kode yang sama seperti di atas kecuali untuk perubahan sederhana ini:

//  Add lib namespace with empty prefix  
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   
Ali B
sumber
13

Jika Anda ingin menghapus namespace Anda mungkin juga ingin menghapus versinya, untuk menghemat pencarian, saya telah menambahkan fungsionalitas itu sehingga kode di bawah ini akan melakukan keduanya.

Saya juga membungkusnya dengan metode umum karena saya membuat file xml yang sangat besar yang terlalu besar untuk diserialkan dalam memori jadi saya telah memecah file keluaran saya dan membuat serial dalam "potongan" yang lebih kecil:

    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
        }
    }
D34
sumber
Hati-hati, StringWriterdefaultnya ke UTF-16 Encoding yang dapat menyebabkan masalah deserialisasi di hilir. using (var reader = XmlReader.Create(stream)){ reader.Read(); }Ini memunculkan pengecualian karena deklarasi menyatakannya sebagai UTF-16 sedangkan konten sebenarnya ditulis sebagai UTF-8. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan
Untuk menyiasati ini dan masih digunakan XmlReader, Anda dapat menggunakan var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);The true akan menggunakan BOM jika ditemukan, jika tidak default yang Anda sediakan.
Tyler StandishMan
9

Saya menyarankan kelas penolong ini:

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
}

:)

Maziar Taheri
sumber
jawaban yang bagus :) saya juga menambahkan aliran baris ini.Position = 0; dan mengembalikan seluruh aliran dalam solusi saya .. berfungsi seperti yang diharapkan - semua tag perlambatan telah dihapus
ymz
Menambahkan argumen ruang nama ke panggilan serializer saja berhasil bagi saya untuk menghapus ruang nama default. Menulis new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})alih-alih new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})adalah cara yang lebih jelas untuk mengkodekannya, menurut pendapat saya.
Suncat2000
5

Jika Anda tidak dapat menyingkirkan atribut xmlns tambahan untuk setiap elemen, saat membuat serial ke xml dari kelas yang dihasilkan (misalnya: ketika xsd.exe digunakan), Anda memiliki sesuatu seperti:

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

maka saya akan berbagi dengan Anda apa yang berhasil untuk saya (campuran dari jawaban sebelumnya dan apa yang saya temukan di sini )

setel secara eksplisit semua xmlns Anda yang berbeda sebagai berikut:

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")

lalu berikan ke serialize tersebut

serializer.Serialize(writer, object, xmlns);

Anda akan memiliki tiga ruang nama yang dideklarasikan di elemen root dan tidak perlu lagi dibuat di elemen lain yang akan diawali dengan semestinya

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...
vinjenzo
sumber
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();
        }
Taurus999able
sumber