Wie kann verhindert werden, dass leere XML-Attribute in der Ausgabe von XNETDocument von .NET ausgegeben werden?

118

Beim Generieren von XML aus XmlDocument in .NET xmlnswird beim ersten Einfügen eines Elements ohne zugeordneten Namespace ein leeres Attribut angezeigt . Wie kann dies verhindert werden?

Beispiel:

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

Ausgabe:

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

Gewünschte Ausgabe:

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

Gibt es eine Lösung für den XmlDocumentCode, die nicht nach dem Konvertieren des Dokuments in eine Zeichenfolge mit auftritt OuterXml?

Mein Grund dafür ist, zu prüfen, ob ich mit XmlDocument-generiertem XML mit dem Standard-XML eines bestimmten Protokolls übereinstimmen kann. Das leere xmlnsAttribut darf einen Parser nicht beschädigen oder verwirren, aber es ist auch in keiner Verwendung vorhanden, die ich von diesem Protokoll gesehen habe.

Neil C. Obremski
quelle

Antworten:

111

Dank der Antwort von Jeremy Lew und ein bisschen mehr Herumspielen habe ich herausgefunden, wie man leere xmlnsAttribute entfernt: Übergeben Sie den Namespace des Stammknotens, wenn Sie einen untergeordneten Knoten erstellen, für den Sie kein Präfix haben möchten . Wenn Sie einen Namespace ohne Präfix im Stammverzeichnis verwenden, müssen Sie denselben Namespace für untergeordnete Elemente verwenden, damit diese auch keine Präfixe haben.

Fester Code:

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

Vielen Dank an alle für all Ihre Antworten, die mich in die richtige Richtung geführt haben!

Neil C. Obremski
quelle
1
Genau. Wenn Sie das <loner> -Element in den Namespace "Whatever: Name-Space-1.0" einfügen, wird das leere xmlns-Attribut (das es in keinen Namespace einfügt) bei der Serialisierung nicht hinzugefügt. Wenn Sie Informationen
Sie
2
Achtung: Elemente benötigen dies (oder das vielleicht bessere doc.DocumentElement.NamespaceURI), geben jedoch keinen Namespace an, für den CreateAttribute()Sie den Namen erhalten, xmlns:psomethingauch wenn es sich um denselben Uri handelt.
Jason Kleban
87

Dies ist eine Variante der Antwort von JeniT (Vielen Dank übrigens!)

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

Dadurch muss der Namespace nicht mehr überall kopiert oder wiederholt werden.

C Johnson
quelle
3
Beste Antwort meiner Meinung nach. Wir müssen nicht wissen, was der Standard-Namespace für Dokumente ist (nützlich, wenn wir keine XML-Datei von Grund auf neu erstellen, dh in Lese- und Änderungsszenarien).
MuiBienCarlota
11

Wenn das <loner>Element in Ihrem Beispiel-XML nicht die xmlnsStandard-Namespace-Deklaration enthält, befindet es sich im whatever:name-space-1.0Namespace und nicht in keinem Namespace. Wenn Sie dies möchten, müssen Sie das Element in diesem Namespace erstellen:

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

Wenn Sie möchten, dass sich das <loner>Element in keinem Namespace befindet, ist das erstellte XML genau das, was Sie benötigen, und Sie sollten sich keine Gedanken über das xmlnsAttribut machen, das automatisch für Sie hinzugefügt wurde.

JeniT
quelle
3
Das Problem liegt bei nicht kompatiblen XML-Parsern (normalerweise von Microsoft), die mit xmnls = "" nicht umgehen können).
Craig Trader
2
/. namens. Sie wollen ihren zufälligen MS-Bashing-Kommentar zurück.
@W. Craig Trader - kann nicht sagen, dass ich darauf als Problem gestoßen bin. Beispiel?
Kev
1
Richtig, ich möchte nicht, dass der <loner /> -Knoten einen Namespace hat, aber ich möchte auch nicht, dass er ein leeres Namespace-Attribut (xmlns) hat. Ich überlege nur, ob ich mit der XML-Ausgabe eines bestimmten Protokolls übereinstimmen kann, das so eingerichtet ist.
Neil C. Obremski
5
Es war kein zufälliges Bashing. Der Microsoft Updater-Anwendungsblock verwendet ein XML-Manifest, um zu bestimmen, was an einen Client geliefert werden soll. Leider kann der Manifest-Parser xmlns = "" nicht verarbeiten. Ich musste einen Postprozessor schreiben, der die leeren xmlns-Attribute entfernt.
Craig Trader
7

Da sich root in einem nicht vordefinierten Namespace befindet, muss jedes untergeordnete Element von root, das keinen Namespace haben möchte, wie in Ihrem Beispiel ausgegeben werden. Die Lösung wäre, dem Stammelement wie folgt vorangestellt zu werden:

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

Code:

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
quelle
Vielen Dank, aber das Hinzufügen des Namespace zum eigentlichen Stamm würde mein XML in Bezug auf das bestimmte Protokoll, mit dem ich arbeite, beschädigen.
Neil C. Obremski
Ah! Ich erkannte mehr, was Sie sagten, und berücksichtigte es, als ich meine eigene Antwort schrieb. Vielen Dank Jeremy
Neil C. Obremski
0

Wenn möglich, erstellen Sie eine Serialisierungsklasse und gehen Sie dann wie folgt vor:

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

Es ist sicherer und Sie können die Namespaces mit Attributen steuern, wenn Sie wirklich mehr Kontrolle benötigen.

ilitirit
quelle
0

Ich habe das Problem mithilfe des Factory-Musters gelöst. Ich habe eine Factory für XElement-Objekte erstellt. Als Parameter für die Instanziierung der Factory habe ich ein XNamespace-Objekt angegeben. Jedes Mal, wenn ein XElement von der Factory erstellt wird, wird der Namespace automatisch hinzugefügt. Hier ist der Code der Fabrik:

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);
    }
}
Brinke
quelle
1
Das OP fragte XmlDocumentnicht danach XDocument.
John Saunders
0

Ja, Sie können das XMLNS vom XmlElement aus verhindern. Erst Zeit schaffen, es kommt: so

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

Ändern Sie den Code: Und übergeben Sie den XML-Namespace wie folgt

C # -Code:

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