Menghilangkan semua namespace xsi dan xsd saat membuat serial objek di .NET?


132

Kode ini terlihat seperti ini:

StringBuilder builder = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
using (XmlWriter xmlWriter = XmlWriter.Create(builder, settings))
{
    XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
    s.Serialize(xmlWriter, objectToSerialize);
}

Dokumen berseri yang dihasilkan meliputi ruang nama, seperti:

<message xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
    xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
    xmlns="urn:something">
 ...
</message>

Untuk menghapus namespace xsi dan xsd, saya dapat mengikuti jawaban dari Bagaimana membuat serialisasi objek ke XML tanpa mendapatkan xmlns = "..."? .

Saya ingin tag pesan saya <message>(tanpa atribut namespace). Bagaimana saya bisa melakukan ini?


2
Saya tahu Anda berpikir ini mungkin membuat xml Anda terlihat lebih baik, tetapi menyediakan ruang nama dan xsd yang sesuai adalah praktik yang lebih baik.

2
Saya ingin xml hanya sebagai <message>, saya berbicara tentang menghilangkan xmlns: xsi dan xmlns: xsd namespaces.
NetSide

5
Sebagai catatan: Secara umum, ini adalah kesalahan bodoh. Ruang nama ada karena suatu alasan, dan menghapus semuanya akan merusak banyak hal. Hal-hal seperti deserialisasi.
John Saunders

66
Perhatikan bahwa terkadang itu bukan kebodohan dan bukan kesalahan. Sebagai contoh, seseorang mungkin perlu membuat fragmen dokumen dan menggabungkannya nanti. Secara pribadi, saya perlu membuat banyak dokumen yang serupa dan sangat besar. Mereka semua memiliki bagian besar yang sama jauh di dalam pohon. Jadi saya harus membuat bagian invarian sebelumnya dan memasukkannya sebagai byte array ketika membuat dokumen. Jadi untuk membuat output lebih mudah dibaca dan lebih kecil saya perlu menghilangkan beberapa deklarasi namespace di bagian dalam karena mereka ada di tingkat yang lebih tinggi.
Dmitry Tashkinov

Jawaban:


233
...
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("","");
s.Serialize(xmlWriter, objectToSerialize, ns);

2
Saya hanya ingin menambahkan bahwa menghapus namespace default dapat memiliki konsekuensi yang tidak diinginkan: misalnya, jika Anda menggunakan atribut XmlInclude untuk membuat serialisasi tipe turunan, ruang nama akan ditambahkan ke masing-masing elemen ini, apakah Anda mau atau tidak, karena mereka diperlukan untuk deserialization
Thomas Levesque

3
Juga, ini tidak menghapus semua ruang nama xml, seperti pertanyaan yang diajukan. Itu hanya menghapus namespace xsi dan xsd, seperti yang disebutkan dalam pertanyaan stackoverflow.com/questions/258960 , yang juga dikutip dalam pertanyaan ini .
Cheeso

1
Juga tidak didukung oleh MS sebagaimana disebutkan dalam jawaban saya sendiri. Ini tidak selalu bekerja, terutama bila jenis Anda dapat digunakan dengan orang lain yang melakukan memiliki ruang nama.
fourpastmidnight

@ThomasLevesque, bagaimana cara menghapus namespace default saat menggunakan atribut XmlInclude?
Jeson Martajaya

4
Dapat disingkat menjadis.Serialize(writer, objectToSerialize, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
Xeevis

27

Ini adalah jawaban kedua dari dua.

Jika Anda ingin menghapus semua ruang nama secara sewenang-wenang dari dokumen selama serialisasi, Anda dapat melakukan ini dengan menerapkan XmlWriter Anda sendiri.

Cara termudah adalah memperoleh dari XmlTextWriter dan mengganti metode StartElement yang memancarkan ruang nama. Metode StartElement dipanggil oleh XmlSerializer ketika memancarkan elemen apa pun, termasuk root. Dengan mengganti namespace untuk setiap elemen, dan menggantinya dengan string kosong, Anda telah menghapus ruang nama dari output.

public class NoNamespaceXmlWriter : XmlTextWriter
{
    //Provide as many contructors as you need
    public NoNamespaceXmlWriter(System.IO.TextWriter output)
        : base(output) { Formatting= System.Xml.Formatting.Indented;}

    public override void WriteStartDocument () { }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        base.WriteStartElement("", localName, "");
    }
}

Misalkan ini adalah tipe:

// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
    // private fields backing the properties
    private int _Epoch;
    private string _Label;

    // explicitly define a distinct namespace for this element
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        set {  _Label= value; } 
        get { return _Label; } 
    }

    // this property will be implicitly serialized to XML using the
    // member name for the element name, and inheriting the namespace from
    // the type.
    public int Epoch
    {
        set {  _Epoch= value; } 
        get { return _Epoch; } 
    }
}

Inilah cara Anda menggunakan hal seperti itu selama serialisasi:

        var o2= new MyTypeWithNamespaces { ..intializers.. };
        var builder = new System.Text.StringBuilder();
        using ( XmlWriter writer = new NoNamespaceXmlWriter(new System.IO.StringWriter(builder)))
        {
            s2.Serialize(writer, o2, ns2);
        }            
        Console.WriteLine("{0}",builder.ToString());

XmlTextWriter agak rusak. Menurut dokumen referensi , ketika ia menulis itu tidak memeriksa yang berikut:

  • Karakter tidak valid dalam nama atribut dan elemen.

  • Karakter Unicode yang tidak sesuai dengan pengkodean yang ditentukan. Jika karakter Unicode tidak sesuai dengan pengkodean yang ditentukan, XmlTextWriter tidak lolos dari karakter Unicode ke entitas karakter.

  • Atribut duplikat.

  • Karakter dalam pengidentifikasi publik DOCTYPE atau pengidentifikasi sistem.

Masalah-masalah ini dengan XmlTextWriter telah ada sejak v1.1 dari .NET Framework, dan mereka akan tetap, untuk kompatibilitas mundur. Jika Anda tidak memiliki masalah dengan masalah tersebut, maka gunakan XmlTextWriter. Tetapi kebanyakan orang menginginkan keandalan yang lebih tinggi.

Untuk mendapatkan itu, sementara masih menekan ruang nama selama serialisasi, alih-alih berasal dari XmlTextWriter, tentukan implementasi konkret XmlWriter abstrak dan 24 metodenya.

Contohnya ada di sini:

public class XmlWriterWrapper : XmlWriter
{
    protected XmlWriter writer;

    public XmlWriterWrapper(XmlWriter baseWriter)
    {
        this.Writer = baseWriter;
    }

    public override void Close()
    {
        this.writer.Close();
    }

    protected override void Dispose(bool disposing)
    {
        ((IDisposable) this.writer).Dispose();
    }

    public override void Flush()
    {
        this.writer.Flush();
    }

    public override string LookupPrefix(string ns)
    {
        return this.writer.LookupPrefix(ns);
    }

    public override void WriteBase64(byte[] buffer, int index, int count)
    {
        this.writer.WriteBase64(buffer, index, count);
    }

    public override void WriteCData(string text)
    {
        this.writer.WriteCData(text);
    }

    public override void WriteCharEntity(char ch)
    {
        this.writer.WriteCharEntity(ch);
    }

    public override void WriteChars(char[] buffer, int index, int count)
    {
        this.writer.WriteChars(buffer, index, count);
    }

    public override void WriteComment(string text)
    {
        this.writer.WriteComment(text);
    }

    public override void WriteDocType(string name, string pubid, string sysid, string subset)
    {
        this.writer.WriteDocType(name, pubid, sysid, subset);
    }

    public override void WriteEndAttribute()
    {
        this.writer.WriteEndAttribute();
    }

    public override void WriteEndDocument()
    {
        this.writer.WriteEndDocument();
    }

    public override void WriteEndElement()
    {
        this.writer.WriteEndElement();
    }

    public override void WriteEntityRef(string name)
    {
        this.writer.WriteEntityRef(name);
    }

    public override void WriteFullEndElement()
    {
        this.writer.WriteFullEndElement();
    }

    public override void WriteProcessingInstruction(string name, string text)
    {
        this.writer.WriteProcessingInstruction(name, text);
    }

    public override void WriteRaw(string data)
    {
        this.writer.WriteRaw(data);
    }

    public override void WriteRaw(char[] buffer, int index, int count)
    {
        this.writer.WriteRaw(buffer, index, count);
    }

    public override void WriteStartAttribute(string prefix, string localName, string ns)
    {
        this.writer.WriteStartAttribute(prefix, localName, ns);
    }

    public override void WriteStartDocument()
    {
        this.writer.WriteStartDocument();
    }

    public override void WriteStartDocument(bool standalone)
    {
        this.writer.WriteStartDocument(standalone);
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        this.writer.WriteStartElement(prefix, localName, ns);
    }

    public override void WriteString(string text)
    {
        this.writer.WriteString(text);
    }

    public override void WriteSurrogateCharEntity(char lowChar, char highChar)
    {
        this.writer.WriteSurrogateCharEntity(lowChar, highChar);
    }

    public override void WriteValue(bool value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(DateTime value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(decimal value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(double value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(int value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(long value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(object value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(float value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteValue(string value)
    {
        this.writer.WriteValue(value);
    }

    public override void WriteWhitespace(string ws)
    {
        this.writer.WriteWhitespace(ws);
    }


    public override XmlWriterSettings Settings
    {
        get
        {
            return this.writer.Settings;
        }
    }

    protected XmlWriter Writer
    {
        get
        {
            return this.writer;
        }
        set
        {
            this.writer = value;
        }
    }

    public override System.Xml.WriteState WriteState
    {
        get
        {
            return this.writer.WriteState;
        }
    }

    public override string XmlLang
    {
        get
        {
            return this.writer.XmlLang;
        }
    }

    public override System.Xml.XmlSpace XmlSpace
    {
        get
        {
            return this.writer.XmlSpace;
        }
    }        
}

Kemudian, berikan kelas turunan yang mengesampingkan metode StartElement, seperti sebelumnya:

public class NamespaceSupressingXmlWriter : XmlWriterWrapper
{
    //Provide as many contructors as you need
    public NamespaceSupressingXmlWriter(System.IO.TextWriter output)
        : base(XmlWriter.Create(output)) { }

    public NamespaceSupressingXmlWriter(XmlWriter output)
        : base(XmlWriter.Create(output)) { }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        base.WriteStartElement("", localName, "");
    }
}

Dan kemudian gunakan penulis ini seperti:

        var o2= new MyTypeWithNamespaces { ..intializers.. };
        var builder = new System.Text.StringBuilder();
        var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
        using ( XmlWriter innerWriter = XmlWriter.Create(builder, settings))
            using ( XmlWriter writer = new NamespaceSupressingXmlWriter(innerWriter))
            {
                s2.Serialize(writer, o2, ns2);
            }            
        Console.WriteLine("{0}",builder.ToString());

Kredit untuk ini ke Oleg Tkachenko .


3
Saya menemukan bahwa saya juga perlu mengganti LookupPrefix(string ns)untuk selalu mengembalikan string kosong untuk menghapus semua deklarasi skema.
Kevin Brock

Ini tidak secara teknis menjawab pertanyaan - Anda menggunakan XmlTextWriter, bukan XmlWriter. Saya perhatikan karena saya ingin menggunakan XmlWriter, untuk XmlWriterSettings yang dapat saya gunakan dengannya.
Abacus

@ Albacus apakah Anda membaca kode? Ini menggunakan XmlWriter dan XmlWriterSettings .
Cheeso

salahku, aku pasti melewatkan itu.
Abacus

Jawaban Hebat, Selain metode yang ditambahkan dari @KevinBrock, saya juga perlu membebani <! - bahasa: lang-cs -> WriteStartAttribute (awalan string, string localName, string ns) sebelum kode saya menghapus semua penempatan nama. Juga perlu dicatat awalan namespace saya berubah dari b2p1 ke p2, yang membuat saya memeriksa metode lain menggunakan awalan.
Mabdullah

15

Setelah membaca dokumentasi Microsoft dan beberapa solusi online, saya telah menemukan solusi untuk masalah ini. Ini berfungsi dengan baik XmlSerializerserialisasi XML bawaan dan kustom via IXmlSerialiazble.

Intinya, saya akan menggunakan MyTypeWithNamespacessampel XML yang sama yang telah digunakan dalam jawaban pertanyaan ini sejauh ini.

[XmlRoot("MyTypeWithNamespaces", Namespace="urn:Abracadabra", IsNullable=false)]
public class MyTypeWithNamespaces
{
    // As noted below, per Microsoft's documentation, if the class exposes a public
    // member of type XmlSerializerNamespaces decorated with the 
    // XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
    // namespaces during serialization.
    public MyTypeWithNamespaces( )
    {
        this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
            // Don't do this!! Microsoft's documentation explicitly says it's not supported.
            // It doesn't throw any exceptions, but in my testing, it didn't always work.

            // new XmlQualifiedName(string.Empty, string.Empty),  // And don't do this:
            // new XmlQualifiedName("", "")

            // DO THIS:
            new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
            // Add any other namespaces, with prefixes, here.
        });
    }

    // If you have other constructors, make sure to call the default constructor.
    public MyTypeWithNamespaces(string label, int epoch) : this( )
    {
        this._label = label;
        this._epoch = epoch;
    }

    // An element with a declared namespace different than the namespace
    // of the enclosing type.
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        get { return this._label; }
        set { this._label = value; }
    }
    private string _label;

    // An element whose tag will be the same name as the property name.
    // Also, this element will inherit the namespace of the enclosing type.
    public int Epoch
    {
        get { return this._epoch; }
        set { this._epoch = value; }
    }
    private int _epoch;

    // Per Microsoft's documentation, you can add some public member that
    // returns a XmlSerializerNamespaces object. They use a public field,
    // but that's sloppy. So I'll use a private backed-field with a public
    // getter property. Also, per the documentation, for this to work with
    // the XmlSerializer, decorate it with the XmlNamespaceDeclarations
    // attribute.
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces Namespaces
    {
        get { return this._namespaces; }
    }
    private XmlSerializerNamespaces _namespaces;
}

Itu saja untuk kelas ini. Sekarang, beberapa keberatan memiliki XmlSerializerNamespacesobjek di suatu tempat di dalam kelas mereka; tetapi seperti yang Anda lihat, saya menyelipkannya dengan rapi di konstruktor default dan mengekspos properti publik untuk mengembalikan ruang nama.

Sekarang, ketika tiba saatnya untuk membuat serialisasi kelas, Anda akan menggunakan kode berikut:

MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);

/******
   OK, I just figured I could do this to make the code shorter, so I commented out the
   below and replaced it with what follows:

// You have to use this constructor in order for the root element to have the right namespaces.
// If you need to do custom serialization of inner objects, you can use a shortened constructor.
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces), new XmlAttributeOverrides(),
    new Type[]{}, new XmlRootAttribute("MyTypeWithNamespaces"), "urn:Abracadabra");

******/
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
    new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });

// I'll use a MemoryStream as my backing store.
MemoryStream ms = new MemoryStream();

// This is extra! If you want to change the settings for the XmlSerializer, you have to create
// a separate XmlWriterSettings object and use the XmlTextWriter.Create(...) factory method.
// So, in this case, I want to omit the XML declaration.
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8; // This is probably the default
// You could use the XmlWriterSetting to set indenting and new line options, but the
// XmlTextWriter class has a much easier method to accomplish that.

// The factory method returns a XmlWriter, not a XmlTextWriter, so cast it.
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
// Then we can set our indenting options (this is, of course, optional).
xtw.Formatting = Formatting.Indented;

// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);

Setelah Anda melakukan ini, Anda harus mendapatkan output berikut:

<MyTypeWithNamespaces>
    <Label xmlns="urn:Whoohoo">myLabel</Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

Saya telah berhasil menggunakan metode ini dalam proyek baru-baru ini dengan hirarki kelas yang mendalam yang diserialisasi ke XML untuk panggilan layanan web. Dokumentasi Microsoft tidak begitu jelas tentang apa yang harus dilakukan dengan XmlSerializerNamespacesanggota yang dapat diakses publik setelah Anda membuatnya, dan begitu banyak orang berpikir itu tidak berguna. Tetapi dengan mengikuti dokumentasi mereka dan menggunakannya dengan cara yang ditunjukkan di atas, Anda dapat menyesuaikan bagaimana XmlSerializer menghasilkan XML untuk kelas Anda tanpa menggunakan perilaku yang tidak didukung atau serialisasi "rolling your own" dengan mengimplementasikan IXmlSerializable.

Ini adalah harapan saya bahwa jawaban ini akan mengistirahatkan, sekali dan untuk semua, bagaimana cara menghilangkan standar xsidan xsdruang nama yang dihasilkan oleh XmlSerializer.

UPDATE: Saya hanya ingin memastikan saya menjawab pertanyaan OP tentang menghapus semua ruang nama. Kode saya di atas akan berfungsi untuk ini; Mari saya tunjukkan bagaimana caranya. Sekarang, dalam contoh di atas, Anda benar-benar tidak bisa menghilangkan semua ruang nama (karena ada dua ruang nama yang digunakan). Di suatu tempat di dokumen XML Anda, Anda harus memiliki sesuatu seperti xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo. Jika kelas dalam contoh adalah bagian dari dokumen yang lebih besar, maka di suatu tempat di atas namespace harus dideklarasikan untuk salah satu (atau keduanya) Abracadbradan Whoohoo. Jika tidak, maka elemen dalam satu atau kedua ruang nama harus didekorasi dengan semacam awalan (Anda tidak dapat memiliki dua ruang nama default, kan?). Jadi, untuk contoh ini, Abracadabraadalah namespace defalt. Saya bisa di dalam MyTypeWithNamespaceskelas saya menambahkan awalan namespace untuk Whoohoonamespace seperti:

public MyTypeWithNamespaces
{
    this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
        new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
        new XmlQualifiedName("w", "urn:Whoohoo")
    });
}

Sekarang, dalam definisi kelas saya, saya menunjukkan bahwa <Label/>elemennya ada di namespace "urn:Whoohoo", jadi saya tidak perlu melakukan apa-apa lagi. Ketika saya sekarang membuat cerita bersambung kelas menggunakan kode serialisasi saya di atas tidak berubah, ini adalah output:

<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
    <w:Label>myLabel</w:Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

Karena <Label>berada dalam ruang nama yang berbeda dari dokumen lainnya, ia harus, bagaimanapun, "didekorasi" dengan ruang nama. Perhatikan bahwa masih ada xsidan xsdruang nama.


"Dokumentasi Microsoft secara eksplisit mengatakan itu tidak didukung." Mau berbagi dimana?
Dave Van den Eynde

Dave, ketika Anda memposting jawaban saya untuk pertanyaan serupa, XmlSerializer: hapus namespace xsi dan xsd yang tidak perlu , tautannya ada di sini: XmlSerializerNamespaces Class .
fourpastmidnight

1
Anda masih meneruskan ruang nama ke metode Serialize. Saya pikir ide menyediakan anggota Publik adalah Anda tidak perlu melakukan itu? Saya tidak bisa membuatnya bekerja tanpa melewati metode Serialize. Dan sayangnya, saya tidak memiliki akses ke pemanggilan metode itu. Saya hanya dapat mengatur instance XmlSerializer untuk digunakan.
naksir

Saya menemukan bahwa sebenarnya XmlWriteryang terkandung dalam XmlMediaTypeFormatteryang memaksa namespace xsi dan xsd ke output saya terlepas. Ini hanya memengaruhi mereka yang menggunakan standar WebApi XmlMediaTypeFormatter. Saya menyalin kode sumber untuk itu, dan memodifikasinya untuk meneruskan properti Namespaces saya ke metode Serialize yang diperlukan untuk mencegah XmlWriterdari secara otomatis menambahkan dua default. Lihat jawaban ini
naksir

@ Crush, jawaban yang Anda tautkan menyesatkan - tidak salah, tetapi pernyataannya tidak semuanya benar. Jika Anda melihat potongan kode pertama dalam jawaban saya, Anda akan melihat komentar yang secara eksplisit menyatakan bagaimana XmlSerializer bekerja ketika Anda mengekspos anggota publik dari tipe yang XmlSerializerNamespacesdihiasi dengan XmlNamespacesDeclarationAttribute. Ini diambil langsung dari MSDN dan pada dasarnya menggunakan ruang nama yang dideklarasikan di tempat yang disediakan oleh standar XmlSerializer.
fourpastmidnight

6

Ini adalah yang pertama dari dua jawaban saya untuk pertanyaan itu.

Jika Anda ingin kontrol yang baik atas ruang nama - misalnya jika Anda ingin menghilangkan beberapa ruang nama tetapi tidak yang lain, atau jika Anda ingin mengganti satu ruang nama dengan yang lain, Anda dapat melakukan ini menggunakan XmlAttributeOverrides .

Misalkan Anda memiliki definisi tipe ini:

// explicitly specify a namespace for this type,
// to be used during XML serialization.
[XmlRoot(Namespace="urn:Abracadabra")]
public class MyTypeWithNamespaces
{
    // private fields backing the properties
    private int _Epoch;
    private string _Label;

    // explicitly define a distinct namespace for this element
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        set {  _Label= value; } 
        get { return _Label; } 
    }

    // this property will be implicitly serialized to XML using the
    // member name for the element name, and inheriting the namespace from
    // the type.
    public int Epoch
    {
        set {  _Epoch= value; } 
        get { return _Epoch; } 
    }
}

Dan pseudo-code serialisasi ini:

        var o2= new MyTypeWithNamespaces() { ..initializers...};
        ns.Add( "", "urn:Abracadabra" );
        XmlSerializer s2 = new XmlSerializer(typeof(MyTypeWithNamespaces));
        s2.Serialize(System.Console.Out, o2, ns);

Anda akan mendapatkan sesuatu seperti XML ini:

<MyTypeWithNamespaces xmlns="urn:Abracadabra">
  <Label xmlns="urn:Whoohoo">Cimsswybclaeqjh</Label>
  <Epoch>97</Epoch>
</MyTypeWithNamespaces>

Perhatikan bahwa ada namespace default pada elemen root, dan ada juga namespace yang berbeda pada elemen "Label". Ruang nama ini ditentukan oleh atribut yang mendekorasi tipe, dalam kode di atas.

Kerangka kerja Serialisasi Xml di .NET mencakup kemungkinan untuk secara eksplisit menimpa atribut yang menghiasi kode aktual. Anda melakukan ini dengan kelas dan teman-teman XmlAttributesOverrides. Misalkan saya memiliki tipe yang sama, dan saya membuat cerita bersambung seperti ini:

        // instantiate the container for all attribute overrides
        XmlAttributeOverrides xOver = new XmlAttributeOverrides();

        // define a set of XML attributes to apply to the root element
        XmlAttributes xAttrs1 = new XmlAttributes();

        // define an XmlRoot element (as if [XmlRoot] had decorated the type)
        // The namespace in the attribute override is the empty string. 
        XmlRootAttribute xRoot = new XmlRootAttribute() { Namespace = ""};

        // add that XmlRoot element to the container of attributes
        xAttrs1.XmlRoot= xRoot;

        // add that bunch of attributes to the container holding all overrides
        xOver.Add(typeof(MyTypeWithNamespaces), xAttrs1);

        // create another set of XML Attributes
        XmlAttributes xAttrs2 = new XmlAttributes();

        // define an XmlElement attribute, for a type of "String", with no namespace
        var xElt = new XmlElementAttribute(typeof(String)) { Namespace = ""};

        // add that XmlElement attribute to the 2nd bunch of attributes
        xAttrs2.XmlElements.Add(xElt);

        // add that bunch of attributes to the container for the type, and
        // specifically apply that bunch to the "Label" property on the type.
        xOver.Add(typeof(MyTypeWithNamespaces), "Label", xAttrs2);

        // instantiate a serializer with the overrides 
        XmlSerializer s3 = new XmlSerializer(typeof(MyTypeWithNamespaces), xOver);

        // serialize
        s3.Serialize(System.Console.Out, o2, ns2);

Hasilnya terlihat seperti ini;

<MyTypeWithNamespaces>
  <Label>Cimsswybclaeqjh</Label>
  <Epoch>97</Epoch>
</MyTypeWithNamespaces>

Anda telah menghapus ruang nama.

Pertanyaan logisnya adalah, dapatkah Anda menghapus semua ruang nama dari tipe arbitrer selama serialisasi, tanpa melalui penggantian eksplisit? Jawabannya adalah YA, dan bagaimana melakukannya adalah dalam tanggapan saya berikutnya.


6
XmlSerializer sr = new XmlSerializer(objectToSerialize.GetType());
TextWriter xmlWriter = new StreamWriter(filename);
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
sr.Serialize(xmlWriter, objectToSerialize, namespaces);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.