Auslassen aller xsi- und xsd-Namespaces beim Serialisieren eines Objekts in .NET?

132

Der Code sieht folgendermaßen aus:

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

Das resultierende serialisierte Dokument enthält Namespaces wie folgt:

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

Um die Namespaces xsi und xsd zu entfernen, kann ich der Antwort unter So serialisieren Sie ein Objekt in XML folgen , ohne xmlns = ”…” zu erhalten. .

Ich möchte mein Nachrichten-Tag als <message>(ohne Namespace-Attribute). Wie kann ich das machen?

NetSide
quelle
2
Ich weiß, dass Sie denken, dies könnte dazu führen, dass Ihre XML-Datei besser aussieht, aber die Bereitstellung von Namespaces und entsprechenden XML-Dateien ist eine bessere Vorgehensweise.
2
Ich möchte meine XML nur als <Nachricht>, ich spreche über das Weglassen von xmlns: xsi und xmlns: xsd Namespaces.
NetSide
5
Für die Aufzeichnung: Im Allgemeinen ist dies ein dummer Fehler. Die Namespaces sind aus einem bestimmten Grund vorhanden, und wenn Sie sie alle entfernen, werden die Dinge kaputt gehen. Dinge wie Deserialisierung.
John Saunders
66
Beachten Sie, dass es manchmal nicht dumm und kein Fehler ist. Beispielsweise muss möglicherweise ein Dokumentfragment generiert und später zusammengesetzt werden. Persönlich musste ich viele ähnliche und sehr große Dokumente erstellen. Alle hatten die gleichen großen Teile tief im Baum. Also musste ich die invarianten Teile vorher generieren und sie beim Generieren der Dokumente als Byte-Arrays einfügen. Um die Ausgabe lesbarer und kleiner zu machen, musste ich einige Namespace-Deklarationen in inneren Teilen weglassen, da sie auf den höheren Ebenen existierten.
Dmitry Tashkinov

Antworten:

233
...
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("","");
s.Serialize(xmlWriter, objectToSerialize, ns);
Thomas Levesque
quelle
2
Ich möchte nur hinzufügen, dass das Entfernen des Standard-Namespace unbeabsichtigte Konsequenzen haben kann: Wenn Sie beispielsweise das XmlInclude-Attribut zum Serialisieren abgeleiteter Typen verwenden, werden die Namespaces zu jedem dieser Elemente hinzugefügt, unabhängig davon, ob Sie dies möchten oder nicht sind notwendig für die Deserialisierung
Thomas Levesque
3
Außerdem werden dadurch nicht alle XML-Namespaces entfernt, wie in der Frage gestellt. Es werden nur die Namespaces xsi und xsd entfernt, wie in der Frage stackoverflow.com/questions/258960 erwähnt , die auch in dieser Frage zitiert wird .
Cheeso
1
Auch nicht von MS unterstützt, wie in meiner eigenen Antwort erwähnt. Es funktioniert nicht immer, vor allem , wenn der Typ mit anderen verwendet werden kann , die tun Namensräume haben.
Fourpastmidnight
@ThomasLevesque, wie entferne ich den Standard-Namespace, während ich das XmlInclude-Attribut verwende?
Jeson Martajaya
4
Kann aufs.Serialize(writer, objectToSerialize, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
Xeevis
27

Dies ist die 2. von zwei Antworten.

Wenn Sie während der Serialisierung nur alle Namespaces willkürlich aus einem Dokument entfernen möchten, können Sie dies tun, indem Sie Ihren eigenen XmlWriter implementieren.

Am einfachsten ist es, von XmlTextWriter abzuleiten und die StartElement-Methode zu überschreiben, die Namespaces ausgibt. Die StartElement-Methode wird vom XmlSerializer aufgerufen, wenn Elemente einschließlich des Stamms ausgegeben werden. Indem Sie den Namespace für jedes Element überschreiben und durch die leere Zeichenfolge ersetzen, haben Sie die Namespaces aus der Ausgabe entfernt.

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

Angenommen, dies ist der Typ:

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

So würden Sie so etwas während der Serialisierung verwenden:

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

Der XmlTextWriter ist allerdings irgendwie kaputt. Laut Referenzdokument wird beim Schreiben nicht Folgendes überprüft:

  • Ungültige Zeichen in Attribut- und Elementnamen.

  • Unicode-Zeichen, die nicht der angegebenen Codierung entsprechen. Wenn die Unicode-Zeichen nicht der angegebenen Codierung entsprechen, maskiert der XmlTextWriter die Unicode-Zeichen nicht in Zeichenentitäten.

  • Doppelte Attribute.

  • Zeichen in der öffentlichen Kennung DOCTYPE oder der Systemkennung.

Diese Probleme mit XmlTextWriter gibt es seit Version 1.1 von .NET Framework und werden aus Gründen der Abwärtskompatibilität bestehen bleiben. Wenn Sie keine Bedenken bezüglich dieser Probleme haben, verwenden Sie auf jeden Fall den XmlTextWriter. Aber die meisten Leute wünschen sich etwas mehr Zuverlässigkeit.

Um dies zu erreichen, definieren Sie eine konkrete Implementierung des abstrakten XmlWriter und seiner 24 Methoden , während Sie Namespaces während der Serialisierung unterdrücken, anstatt von XmlTextWriter abzuleiten .

Ein Beispiel ist hier:

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

Geben Sie dann eine abgeleitete Klasse an, die die StartElement-Methode wie zuvor überschreibt:

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

Und dann benutze diesen Schreiber so:

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

Gutschrift dafür an Oleg Tkachenko .

Cheeso
quelle
3
Ich stellte fest, dass ich auch überschreiben musste, LookupPrefix(string ns)um immer eine leere Zeichenfolge zurückzugeben, um alle Schemadeklarationen zu entfernen.
Kevin Brock
Dies beantwortet die Frage technisch nicht - Sie verwenden XmlTextWriter, nicht XmlWriter. Ich bemerke, weil ich XmlWriter für die XmlWriterSettings verwenden möchte, die ich damit verwenden kann.
Abacus
@Abacus hast du den Code gelesen? Es verwendet XmlWriter und XmlWriterSettings .
Cheeso
mein schlechtes, das muss ich verpasst haben.
Abacus
Tolle Antwort: Zusätzlich zu der hinzugefügten Methode von @KevinBrock musste ich auch das <! - language: lang-cs -> WriteStartAttribute (Zeichenfolgenpräfix, Zeichenfolge localName, Zeichenfolge ns) überladen, bevor mein Code alle Zeichen entfernen würde Namespace. Erwähnenswert ist auch, dass meine Namespace-Präfixe von b2p1 auf p2 geändert wurden, was mich dazu veranlasste, mithilfe von Präfixen nach anderen Methoden zu suchen.
Mabdullah
15

Nachdem ich die Dokumentation von Microsoft und verschiedene Lösungen online gelesen habe, habe ich die Lösung für dieses Problem gefunden. Es funktioniert sowohl mit der integrierten XmlSerializerals auch mit der benutzerdefinierten XML-Serialisierung über IXmlSerialiazble.

Ich werde also dasselbe MyTypeWithNamespacesXML-Beispiel verwenden, das bisher in den Antworten auf diese Frage verwendet wurde.

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

Das ist alles für diese Klasse. Nun hatten einige Einwände dagegen, XmlSerializerNamespacesirgendwo in ihren Klassen ein Objekt zu haben; Aber wie Sie sehen, habe ich es ordentlich in den Standardkonstruktor gesteckt und eine öffentliche Eigenschaft verfügbar gemacht, um die Namespaces zurückzugeben.

Wenn es Zeit ist, die Klasse zu serialisieren, verwenden Sie den folgenden Code:

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

Sobald Sie dies getan haben, sollten Sie die folgende Ausgabe erhalten:

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

Ich habe diese Methode kürzlich in einem Projekt mit einer tiefen Hierarchie von Klassen erfolgreich verwendet, die für Webdienstaufrufe in XML serialisiert werden. In der Dokumentation von Microsoft ist nicht klar, was mit dem öffentlich zugänglichen XmlSerializerNamespacesMitglied zu tun ist, wenn Sie es erstellt haben, und so viele halten es für nutzlos. Wenn Sie jedoch der Dokumentation folgen und sie auf die oben gezeigte Weise verwenden, können Sie anpassen, wie der XmlSerializer XML für Ihre Klassen generiert, ohne auf nicht unterstütztes Verhalten zurückgreifen oder Ihre eigene Serialisierung durch Implementierung "rollen" zu lassen IXmlSerializable.

Ich hoffe, dass diese Antwort ein für alle Mal zum Erliegen kommt, wie der Standard xsiund die xsdNamespaces, die von der XmlSerializer.

UPDATE: Ich möchte nur sicherstellen, dass ich die Frage des OP zum Entfernen aller Namespaces beantwortet habe. Mein Code oben wird dafür funktionieren; lass mich dir zeigen wie. Im obigen Beispiel können Sie wirklich nicht alle Namespaces entfernen (da zwei Namespaces verwendet werden). Irgendwo in Ihrem XML-Dokument benötigen Sie so etwas wie xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo. Wenn die Klasse im Beispiel Teil eines größeren Dokuments ist, muss irgendwo über einem Namespace für eines von (oder für beide) Abracadbraund deklariert werden Whoohoo. Wenn nicht, muss das Element in einem oder beiden Namespaces mit einem Präfix versehen sein (Sie können nicht zwei Standard-Namespaces haben, oder?). In diesem Beispiel Abracadabrahandelt es sich also um den Defalt-Namespace. Ich könnte in meiner MyTypeWithNamespacesKlasse ein Namespace-Präfix für den WhoohooNamespace wie folgt hinzufügen :

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

In meiner Klassendefinition habe ich nun angegeben, dass sich das <Label/>Element im Namespace befindet "urn:Whoohoo", sodass ich nichts weiter tun muss. Wenn ich jetzt die Klasse mit meinem obigen Serialisierungscode unverändert serialisiere, ist dies die Ausgabe:

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

Da <Label>es sich in einem anderen Namespace als der Rest des Dokuments befindet, muss es in gewisser Weise mit einem Namespace "dekoriert" werden. Beachten Sie, dass es noch keine sind xsiund xsdNamensräume.

vier Mitternacht
quelle
"In der Dokumentation von Microsoft wird ausdrücklich angegeben, dass dies nicht unterstützt wird." Möchtest du wo teilen?
Dave Van den Eynde
Dave, wie Sie in meiner Antwort auf eine ähnliche Frage, XmlSerializer , gepostet haben: Entfernen Sie unnötige xsi- und xsd-Namespaces . Der Link befindet sich hier: XmlSerializerNamespaces-Klasse .
Fourpastmidnight
1
Sie übergeben die Namespaces weiterhin an die Serialize-Methode. Ich dachte, die Idee, ein öffentliches Mitglied zur Verfügung zu stellen, wäre, dass Sie das nicht tun müssten? Ich kann es jedoch nicht zum Laufen bringen, ohne es an die Serialize-Methode zu übergeben. Und leider habe ich keinen Zugriff auf diesen Methodenaufruf. Ich kann nur die zu verwendende XmlSerializer-Instanz festlegen.
Crush
Ich fand heraus, dass es tatsächlich das XmlWriterist, was in dem enthalten ist, das die XmlMediaTypeFormatterNamespaces xsi und xsd unabhängig davon in meine Ausgabe zwingt. Dies betrifft nur diejenigen, die die Standardeinstellungen von WebApi verwenden XmlMediaTypeFormatter. Ich habe den Quellcode dafür kopiert und ihn so geändert, dass meine Namespaces-Eigenschaft an die Serialize-Methode übergeben wird, um zu verhindern, dass XmlWriterdie beiden Standardeinstellungen automatisch hinzugefügt werden. Siehe diese Antwort
Crush
@crush, diese Antwort, auf die Sie verlinkt haben, ist irreführend - nicht falsch, aber ihre Behauptungen sind nicht alle richtig. Wenn Sie sich das erste Code-Snippet in meiner Antwort ansehen, sehen Sie einen Kommentar, der explizit angibt, wie der XmlSerializer funktioniert, wenn Sie ein öffentliches Mitglied des Typs verfügbar machen XmlSerializerNamespaces, das mit dem dekoriert ist XmlNamespacesDeclarationAttribute. Dies wurde direkt von MSDN übernommen und verwendet im Wesentlichen die deklarierten Namespaces anstelle der von der XmlSerializer.
vier vergangene Nacht
6

Dies ist die erste meiner beiden Antworten auf die Frage.

Wenn Sie die Namespaces genau steuern möchten, z. B. wenn Sie einige davon weglassen möchten, andere jedoch nicht, oder wenn Sie einen Namespace durch einen anderen ersetzen möchten, können Sie dies mit XmlAttributeOverrides tun .

Angenommen, Sie haben diese Typdefinition:

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

Und dieser Serialisierungs-Pseudocode:

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

Sie würden so etwas wie XML erhalten:

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

Beachten Sie, dass das Stammelement einen Standard-Namespace und das Element "Label" einen eindeutigen Namespace enthält. Diese Namespaces wurden durch die Attribute bestimmt, die den Typ im obigen Code schmücken.

Das XML-Serialisierungsframework in .NET bietet die Möglichkeit, die Attribute, die den eigentlichen Code schmücken , explizit zu überschreiben . Sie tun dies mit der XmlAttributesOverrides-Klasse und Freunden. Angenommen, ich habe denselben Typ und serialisiere ihn folgendermaßen:

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

Das Ergebnis sieht so aus;

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

Sie haben die Namespaces entfernt.

Eine logische Frage ist, ob Sie während der Serialisierung alle Namespaces von beliebigen Typen entfernen können, ohne die expliziten Überschreibungen zu durchlaufen. Die Antwort ist JA, und wie es geht, ist in meiner nächsten Antwort.

Cheeso
quelle
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);
Tejas
quelle