Frage

Ich habe eine Situation, wo ich eine XML-Datei, die ich will nicht zu ändern. Die AddAnnotation Funktion in XElement-Klasse bietet eine Option Speicher nur Daten hinzuzufügen, die nicht serialisiert und nicht Teil des XML.

Ich möchte in der Lage, diese Anmerkungen zu speichern (zB auf eine andere XML-Datei) und dann sowohl die XML und die Anmerkungen, um zu deserialisieren das gleiche Objekt zu bekommen was ich hatte.

Ich will nicht die ursprüngliche xml ändern, und das ist der Grund, dass ich Anmerkungen verwenden.

Um es zusammenzufassen, ich möchte benutzerdefinierte Daten in eine XML-Datei in der Lage sein, hinzuzufügen. Diese Daten werden nicht ein Teil des xml sein, wenn ich es serialisiert werden oder es wird ein Teil des xml sein, aber ich wäre in der Lage, die ursprüngliche xml leicht abgerufen werden.

Haben Sie eine Empfehlung, wie ich so etwas tun kann?

Edit: Soll ich XML-Verarbeitungsanweisungen verwenden? Verarbeiten Anweisungen für diese Art der Nutzung gedacht?

War es hilfreich?

Lösung

Es klingt für mich wie der einfachste Ansatz reguläre Knoten zu verwenden wäre, aber in einem anderen XML-Namespace - d. H

<foo standardAttrubute="abc" myData:customAttribute="def">
    <standardElement>ghi</standardElement >
    <myData:customElement>jkl</myData:customElement>
</foo>

(wobei myData ist ein xmlns alias für die Namespace-uri)

In vielen Fällen Leser nur für Daten überprüfen in ihre Namensraum (oder die default / blank Namensraum.) - Werte in einem eigenen Namensraum werden übersprungen allgemein

erhalten Sie die ursprünglichen XML-Pack, ein einfacher Ansatz wäre es durch eine Xslt auszuführen, die nur den Standard / ursprünglichen Namensraum respektiert.


XNamespace myData = XNamespace.Get("http://mycustomdata/");
XElement el = new XElement("foo",
    new XAttribute(XNamespace.Xmlns + "myData", myData.NamespaceName),
    new XAttribute("standardAttribute", "abc"),
    new XAttribute(myData + "customAttribute", "def"),
    new XElement("standardElement", "ghi"),
    new XElement(myData + "customAttribute", "jkl"));
string s = el.ToString();

Um solche Daten aus einem XElement zu entfernen, vielleicht:

    static void Strip(XElement el, XNamespace ns) {
        List<XElement> remove = new List<XElement>();
        foreach (XElement child in el.Elements()) {
            if (child.Name.Namespace == ns) {
                remove.Add(child);
            } else {
                Strip(child, ns);
            }
        }
        remove.ForEach(child => child.Remove());

        foreach (XAttribute child in
            (from a in el.Attributes()
             where a.Name.Namespace == ns
             select a).ToList()) {
            child.Remove();
        }
    }

Andere Tipps

Die ursprüngliche Frage verwendet, um das Wort „Serialize“, aber dann auch XElement und Annotation erwähnt. Für mich sind das zwei verschiedene Dinge.

Wenn Sie wirklich das XmlSerializer verwenden möchten:
Was ich tun würde, ist XmlAttributeOverrides verwenden, um die Serialisierung zu unterscheiden. Mit den XmlAttributeOverrides können Sie zur Laufzeit programmatisch, außer Kraft setzen, um die XML-Serialisierung Attribute, die Ihre Arten dekorieren.

In Ihrem Typ, können Sie ein Feld / Eigenschaft haben, dass die Anmerkung / Dokumentation halten soll. Dekorieren Sie, dass mit XmlIgnore. Dann erstellen Sie eine Instanz der XmlSerializer, die keine Überschreibungen akzeptiert. Die Anmerkung wird nicht serialisiert oder deserialisiert werden. Erstellen Sie eine andere Instanz der XmlSerializer für diesen Typ, ein XmlAttributeOverrides Objekt. Geben Sie eine Überschreibung für die XmlIgnore'd Eigenschaft (Verwendung XmlElementAttribute) sowie Überschreibungen für alle Attribute auf keines der anderen Mitglieder (Verwendung XmlIgnore = true).

serialisiert die Instanz zweimal, eines mit jedem Serializer.


Edit: hier ist der Code:

public class DTO
{
    [XmlIgnore]
    public string additionalInformation;

    [XmlElement(Order=1)]
    public DateTime stamp;

    [XmlElement(Order=2)]
    public string name;

    [XmlElement(Order=3)]
    public double value;

    [XmlElement(Order=4)]
    public int index;
}



public class OverridesDemo
{ 
    public void Run()
    {
        DTO dto = new DTO
            {
                additionalInformation = "This will bbe serialized separately",
                stamp = DateTime.UtcNow,
                name = "Marley",
                value = 72.34,
                index = 7
            };


        // ---------------------------------------------------------------
        // 1. serialize normally
        // this will allow us to omit the xmlns:xsi namespace
        var ns = new XmlSerializerNamespaces();
        ns.Add( "", "" );

        XmlSerializer s1 = new XmlSerializer(typeof(DTO));

        var builder = new System.Text.StringBuilder();
        var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };

        Console.WriteLine("\nSerialize using the in-line attributes: ");
        using ( XmlWriter writer = XmlWriter.Create(builder, settings))
        {
            s1.Serialize(writer, dto, ns);
        }
        Console.WriteLine("{0}",builder.ToString());
        Console.WriteLine("\n");            
        // ---------------------------------------------------------------

        // ---------------------------------------------------------------
        // 2. serialize with attribute overrides
        // use a non-empty default namespace
        ns = new XmlSerializerNamespaces();
        string myns = "urn:www.example.org";
        ns.Add( "", myns);

        XmlAttributeOverrides overrides = new XmlAttributeOverrides();

        XmlAttributes attrs = new XmlAttributes();
        // override the (implicit) XmlRoot attribute
        XmlRootAttribute attr1 = new XmlRootAttribute
            {
                Namespace = myns,
                ElementName = "DTO-Annotations",
            };
        attrs.XmlRoot = attr1;

        overrides.Add(typeof(DTO), attrs);
        // "un-ignore" the first property
        // define an XmlElement attribute, for a type of "String", with no namespace
        var a2 = new XmlElementAttribute(typeof(String)) { ElementName="note", Namespace = myns };

        // add that XmlElement attribute to the 2nd bunch of attributes
        attrs = new XmlAttributes();
        attrs.XmlElements.Add(a2);
        attrs.XmlIgnore = false; 

        // add that bunch of attributes to the container for the type, and
        // specifically apply that bunch to the "additionalInformation" property 
        // on the type.
        overrides.Add(typeof(DTO), "additionalInformation", attrs);

        // now, XmlIgnore all the other properties
        attrs = new XmlAttributes();
        attrs.XmlIgnore = true;       
        overrides.Add(typeof(DTO), "stamp", attrs);
        overrides.Add(typeof(DTO), "name",  attrs);
        overrides.Add(typeof(DTO), "value", attrs);
        overrides.Add(typeof(DTO), "index", attrs);

        // create a serializer using those xml attribute overrides
        XmlSerializer s2 = new XmlSerializer(typeof(DTO), overrides);

        Console.WriteLine("\nSerialize using the override attributes: ");
        builder.Length = 0;
        using ( XmlWriter writer = XmlWriter.Create(builder, settings))
        {
            s2.Serialize(writer, dto, ns);
        }
        Console.WriteLine("{0}",builder.ToString());
        Console.WriteLine("\n");            
        // ---------------------------------------------------------------
    }
}

Ausgabe, mit der in-line-Attribute:

<DTO>
  <stamp>2009-06-30T02:17:35.918Z</stamp>
  <name>Marley</name>
  <value>72.34</value>
  <index>7</index>
</DTO>

Ausgabe, die Überschreibung mit Attributen:

<DTO-Annotations xmlns="urn:www.example.org">
  <note>This will bbe serialized separately</note>
</DTO-Annotations>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top