Come impedire attributi xmlns vuoti nell'output da XmlDocument di .NET?


118

Quando si genera XML da XmlDocument in .NET, viene visualizzato un xmlnsattributo vuoto la prima volta che viene inserito un elemento senza uno spazio dei nomi associato; come si può prevenire questo?

Esempio:

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

Produzione:

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

Uscita desiderata :

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

Esiste una soluzione applicabile al XmlDocumentcodice, non qualcosa che si verifica dopo aver convertito il documento in una stringa con OuterXml?

Il mio ragionamento per farlo è vedere se posso abbinare l'XML standard di un particolare protocollo usando l'XML generato da XmlDocument. L' xmlnsattributo vuoto non può rompere o confondere un parser, ma non è nemmeno presente in alcun utilizzo che ho visto di questo protocollo.

Risposte:


111

Grazie alla risposta di Jeremy Lew e un po 'più di gioco, ho capito come rimuovere gli xmlnsattributi vuoti : passare lo spazio dei nomi del nodo radice quando si crea un nodo figlio su cui non si desidera avere un prefisso. Utilizzando uno spazio dei nomi senza prefisso ai mezzi radice che è necessario utilizzare lo stesso spazio dei nomi su elementi figli per loro anche non hanno prefissi.

Codice fisso:

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

Grazie a tutti per tutte le vostre risposte che mi hanno portato nella giusta direzione!


1
Precisamente. Mettere l'elemento <loner> nello spazio dei nomi "any: name-space-1.0" significa che l'attributo xmlns vuoto (che lo mette in nessuno spazio dei nomi) non verrà aggiunto ad esso quando viene serializzato. Se hai bisogno di rinfrescarti su come funzionano gli spazi dei nomi, dai un'occhiata a jclark.com/xml/xmlns.htm
JeniT

2
Attenzione: gli elementi hanno bisogno di questo (o forse meglio doc.DocumentElement.NamespaceURI) ma non specificare uno spazio dei nomi perché CreateAttribute()otterrai xmlns:psomethinganche se è lo stesso uri.
Jason Kleban

87

Questa è una variante della risposta di JeniT (Grazie mille a proposito!)

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

Ciò elimina la necessità di copiare o ripetere lo spazio dei nomi ovunque.


3
Migliore risposta secondo me. Non dobbiamo sapere qual è lo spazio dei nomi predefinito del documento (utile quando non creiamo un file xml da zero, ad esempio in scenari di lettura e modifica).
MuiBienCarlota

11

Se l' <loner>elemento nel tuo XML di esempio non avesse la xmlnsdichiarazione dello spazio dei nomi predefinito su di esso, allora sarebbe nello whatever:name-space-1.0spazio dei nomi piuttosto che in nessuno spazio dei nomi. Se è quello che vuoi, devi creare l'elemento in quello spazio dei nomi:

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

Se vuoi che l' <loner>elemento non si trovi in ​​uno spazio dei nomi, l'XML che è stato prodotto è esattamente ciò di cui hai bisogno e non dovresti preoccuparti xmlnsdell'attributo che è stato aggiunto automaticamente per te.


3
Il problema risiede con parser XML non conformi (in genere da Microsoft) che non possono far fronte a xmnls = "").
Craig Trader

2
/. chiamato. Vogliono indietro il loro commento casuale contro la SM.

@W. Craig Trader - non posso dire di aver riscontrato questo problema. Esempio?
Kev

1
Esatto, non voglio che il nodo <loner /> abbia uno spazio dei nomi, ma non voglio nemmeno che abbia un attributo spazio dei nomi vuoto (xmlns). Il mio ragionamento è solo per vedere se posso abbinare l'output XML di un particolare protocollo che è configurato in questo modo.
Neil C.Obremski,

5
Non è stato un attacco casuale. Il blocco dell'applicazione Microsoft Updater utilizza un manifest XML per determinare cosa fornire a un client. Sfortunatamente, il parser Manifest non può far fronte a xmlns = ""; Ho dovuto scrivere un post-processore che eliminasse gli attributi xmlns vuoti.
Craig Trader,

7

Dato che root si trova in uno spazio dei nomi non prefissato, qualsiasi figlio di root che desidera essere senza spazio dei nomi deve essere visualizzato come il tuo esempio. La soluzione sarebbe anteporre l'elemento radice in questo modo:

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

codice:

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

Grazie, ma l'aggiunta dello spazio dei nomi alla radice effettiva interromperebbe il mio XML in relazione al particolare protocollo con cui sto lavorando.
Neil C.Obremski

Ah! Ho capito di più quello che stavi dicendo e ne ho tenuto conto quando ho scritto la mia risposta. Grazie Jeremy
Neil C. Obremski

0

Se possibile, crea una classe di serializzazione quindi fai:

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

È più sicuro e puoi controllare gli spazi dei nomi con attributi se hai davvero bisogno di più controllo.


0

Ho risolto il problema utilizzando il Factory Pattern. Ho creato una factory per gli oggetti XElement. Come parametro per l'istanza della factory ho specificato un oggetto XNamespace. Quindi, ogni volta che un XElement viene creato dalla fabbrica, lo spazio dei nomi verrà aggiunto automaticamente. Ecco il codice della fabbrica:

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

1
L'OP stava chiedendo XmlDocument, no XDocument.
John Saunders

0

Sì, puoi impedire l'XMLNS da XmlElement. Il primo tempo di creazione sta arrivando: così

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

Modificare il codice: e passare lo spazio dei nomi xml in questo modo

Codice C #:

XmlElement bookElement = xdoc.CreateElement("trkpt", "http://www.topografix.com/GPX/1/1");
bookElement.SetAttribute("lat", "30.53597");
bookElement.SetAttribute("lon", "97.753324");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.