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?
c#
.net
xml-serialization
NetSide
sumber
sumber
Jawaban:
sumber
s.Serialize(writer, objectToSerialize, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
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.
Misalkan ini adalah tipe:
Inilah cara Anda menggunakan hal seperti itu selama serialisasi:
XmlTextWriter agak rusak. Menurut dokumen referensi , ketika ia menulis itu tidak memeriksa yang berikut:
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:
Kemudian, berikan kelas turunan yang mengesampingkan metode StartElement, seperti sebelumnya:
Dan kemudian gunakan penulis ini seperti:
Kredit untuk ini ke Oleg Tkachenko .
sumber
LookupPrefix(string ns)
untuk selalu mengembalikan string kosong untuk menghapus semua deklarasi skema.XmlWriter
danXmlWriterSettings
.Setelah membaca dokumentasi Microsoft dan beberapa solusi online, saya telah menemukan solusi untuk masalah ini. Ini berfungsi dengan baik
XmlSerializer
serialisasi XML bawaan dan kustom viaIXmlSerialiazble
.Intinya, saya akan menggunakan
MyTypeWithNamespaces
sampel XML yang sama yang telah digunakan dalam jawaban pertanyaan ini sejauh ini.Itu saja untuk kelas ini. Sekarang, beberapa keberatan memiliki
XmlSerializerNamespaces
objek 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:
Setelah Anda melakukan ini, Anda harus mendapatkan output berikut:
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
XmlSerializerNamespaces
anggota 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 mengimplementasikanIXmlSerializable
.Ini adalah harapan saya bahwa jawaban ini akan mengistirahatkan, sekali dan untuk semua, bagaimana cara menghilangkan standar
xsi
danxsd
ruang nama yang dihasilkan olehXmlSerializer
.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)Abracadbra
danWhoohoo
. 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,Abracadabra
adalah namespace defalt. Saya bisa di dalamMyTypeWithNamespaces
kelas saya menambahkan awalan namespace untukWhoohoo
namespace seperti: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:Karena
<Label>
berada dalam ruang nama yang berbeda dari dokumen lainnya, ia harus, bagaimanapun, "didekorasi" dengan ruang nama. Perhatikan bahwa masih adaxsi
danxsd
ruang nama.sumber
XmlWriter
yang terkandung dalamXmlMediaTypeFormatter
yang memaksa namespace xsi dan xsd ke output saya terlepas. Ini hanya memengaruhi mereka yang menggunakan standar WebApiXmlMediaTypeFormatter
. Saya menyalin kode sumber untuk itu, dan memodifikasinya untuk meneruskan properti Namespaces saya ke metode Serialize yang diperlukan untuk mencegahXmlWriter
dari secara otomatis menambahkan dua default. Lihat jawaban iniXmlSerializerNamespaces
dihiasi denganXmlNamespacesDeclarationAttribute
. Ini diambil langsung dari MSDN dan pada dasarnya menggunakan ruang nama yang dideklarasikan di tempat yang disediakan oleh standarXmlSerializer
.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:
Dan pseudo-code serialisasi ini:
Anda akan mendapatkan sesuatu seperti XML ini:
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:
Hasilnya terlihat seperti ini;
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.
sumber
sumber