Bagaimana cara mencegah atribut xmlns kosong dalam output dari XmlDocument .NET?

118

Saat membuat XML dari XmlDocument di .NET, xmlnsatribut kosong muncul saat pertama kali elemen tanpa namespace terkait dimasukkan; bagaimana ini bisa dicegah?

Contoh:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root",
    "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner"));
Console.WriteLine(xml.OuterXml);

Keluaran:

<root xmlns="whatever:name-space-1.0"><loner xmlns="" /></root>

Output yang diinginkan :

<root xmlns="whatever:name-space-1.0"><loner /></root>

Apakah ada solusi yang berlaku untuk XmlDocumentkode tersebut, bukan sesuatu yang terjadi setelah mengonversi dokumen menjadi string OuterXml?

Alasan saya melakukan ini adalah untuk melihat apakah saya dapat mencocokkan XML standar dari protokol tertentu menggunakan XML yang dihasilkan XmlDocument. xmlnsAtribut blank mungkin tidak merusak atau membingungkan parser, tetapi juga tidak ada dalam penggunaan apa pun yang pernah saya lihat dari protokol ini.

Neil C. Obremski
sumber

Jawaban:

111

Berkat jawaban Jeremy Lew dan sedikit lebih banyak bermain-main, saya menemukan cara menghapus xmlnsatribut kosong : berikan namespace node root saat membuat node anak yang Anda tidak ingin memiliki awalan. Menggunakan namespace tanpa awalan di root berarti Anda perlu menggunakan namespace yang sama pada elemen turunan agar mereka juga tidak memiliki awalan.

Kode Tetap:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root", "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner", "whatever:name-space-1.0")); 
Console.WriteLine(xml.OuterXml);

Terima kasih semuanya atas semua jawaban Anda yang membawa saya ke arah yang benar!

Neil C. Obremski
sumber
1
Tepat. Menempatkan elemen <loner> di namespace "anything: name-space-1.0" berarti bahwa atribut xmlns kosong (yang tidak menempatkannya di namespace) tidak akan ditambahkan ke dalamnya saat serialisasi. Jika Anda perlu menyegarkan tentang cara kerja namespace, lihat di jclark.com/xml/xmlns.htm
JeniT
2
Hati-hati: Elemen membutuhkan ini (atau mungkin lebih baik doc.DocumentElement.NamespaceURI) tetapi jangan tentukan namespace untuk CreateAttribute()Anda akan mendapatkan xmlns:psomethingbahkan jika itu adalah uri yang sama.
Jason Kleban
87

Ini adalah varian dari jawaban JeniT (Terima kasih banyak btw!)

XmlElement new_element = doc.CreateElement("Foo", doc.DocumentElement.NamespaceURI);

Ini menghilangkan keharusan untuk menyalin atau mengulang namespace di mana-mana.

C Johnson
sumber
3
Respon terbaik menurut saya. Kita tidak perlu tahu apa itu namespace default dokumen (berguna jika kita tidak membuat file xml dari awal, misalnya dalam skenario baca dan modifikasi).
MuiBienCarlota
11

Jika <loner>elemen dalam contoh XML Anda tidak memiliki xmlnsdeklarasi ruang nama default di atasnya, maka elemen itu akan berada di whatever:name-space-1.0ruang nama daripada tidak ada di ruang nama. Jika itu yang Anda inginkan, Anda perlu membuat elemen di namespace itu:

xml.CreateElement("loner", "whatever:name-space-1.0")

Jika Anda ingin <loner>elemen tidak ada di namespace, maka XML yang telah dibuat adalah yang Anda butuhkan, dan Anda tidak perlu khawatir tentang xmlnsatribut yang telah ditambahkan secara otomatis untuk Anda.

JeniT
sumber
3
Masalahnya terletak pada parser XML yang tidak memenuhi standar (biasanya dari Microsoft) yang tidak dapat menangani xmnls = "").
Craig Trader
2
/. dipanggil. Mereka ingin komentar bashing acak mereka dibalas.
@W. Craig Trader - saya tidak bisa mengatakan saya mengalami itu sebagai masalah. Contoh?
Kev
1
Benar, saya tidak ingin node <loner /> memiliki namespace, tetapi saya juga tidak ingin node tersebut memiliki atribut namespace kosong (xmlns). Alasan saya hanya untuk melihat apakah saya dapat mencocokkan output XML dari protokol tertentu yang diatur seperti ini.
Neil C.Obremski
5
Itu bukan bashing acak. Blok Aplikasi Microsoft Updater menggunakan XML Manifest untuk menentukan apa yang akan dikirim ke klien. Sayangnya, pengurai Manifes tidak dapat menangani xmlns = ""; Saya harus menulis prosesor pasca yang akan menghapus atribut xmlns kosong.
Craig Trader
7

Karena root berada dalam namespace yang tidak diperbaiki, setiap turunan dari root yang ingin dihapus namespace harus dikeluarkan seperti contoh Anda. Solusinya adalah dengan mengawali elemen root seperti ini:

<w:root xmlns:w="whatever:name-space-1.0">
   <loner/>
</w:root>

kode:

XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement( "w", "root", "whatever:name-space-1.0" );
doc.AppendChild( root );
root.AppendChild( doc.CreateElement( "loner" ) );
Console.WriteLine(doc.OuterXml);
jlew
sumber
Terima kasih, tetapi menambahkan namespace ke root sebenarnya akan merusak XML saya sehubungan dengan protokol tertentu yang saya kerjakan.
Neil C.Obremski
Ah! Saya lebih menyadari apa yang Anda katakan dan memperhitungkannya saat menulis jawaban saya sendiri. Terima kasih Jeremy
Neil C. Obremski
0

Jika memungkinkan, buat kelas serialisasi lalu lakukan:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(yourType);
serializer.Serialize(xmlTextWriter, someObject, ns);

Ini lebih aman, dan Anda dapat mengontrol ruang nama dengan atribut jika Anda benar-benar membutuhkan lebih banyak kontrol.

ilitirit
sumber
0

Saya telah memecahkan masalah dengan menggunakan Pola Pabrik. Saya membuat pabrik untuk objek XElement. Sebagai parameter untuk instansiasi pabrik, saya telah menetapkan objek XNamespace. Jadi, setiap XElement dibuat oleh pabrik, namespace akan ditambahkan secara otomatis. Berikut kode pabriknya:

internal class XElementFactory
{
    private readonly XNamespace currentNs;

    public XElementFactory(XNamespace ns)
    {
        this.currentNs = ns;
    }

    internal XElement CreateXElement(String name, params object[] content)
    {
        return new XElement(currentNs + name, content);
    }
}
tepi jurang
sumber
1
OP bertanya tentang XmlDocument, bukan XDocument.
John Saunders
0

Ya, Anda dapat mencegah XMLNS dari XmlElement. Menciptakan pertama kali akan datang: seperti itu

<trkpt lat="30.53597" lon="-97.753324" xmlns="">
    <ele>249.118774</ele>
    <time>2006-05-05T14:34:44Z</time>
</trkpt>

Ubah kode: Dan berikan namespace xml seperti ini

Kode C #:

XmlElement bookElement = xdoc.CreateElement("trkpt", "http://www.topografix.com/GPX/1/1");
bookElement.SetAttribute("lat", "30.53597");
bookElement.SetAttribute("lon", "97.753324");
Debabrata Ghosh
sumber