Domanda

Ho una situazione in cui ho un file XML che io non voglio modificare. La funzione AddAnnotation in classe XElement fornisce un'opzione per aggiungere i dati di sola memoria che non è serializzato e non fa parte del XML.

Voglio essere in grado di salvare queste annotazioni (per esempio: in un altro file XML) e poi per deserializzare sia il codice XML e le annotazioni in modo da ottenere lo stesso oggetto che avevo.

Non voglio cambiare il codice XML originale e questo è il motivo per cui io uso le annotazioni.

In sintesi, voglio essere in grado di aggiungere dati personalizzati in un file XML. Questi dati non sarà una parte del XML quando ho serializzare o sarà una parte del xml, ma sarebbe in grado di recuperare l'XML originale con facilità.

Avete qualche consiglio come posso fare una cosa simile?

Modifica Dovrei usare le istruzioni di elaborazione XML? Sono le istruzioni di elaborazione previsti per questo tipo di utilizzo?

È stato utile?

Soluzione

Sembra a me come l'approccio più semplice sarebbe quella di utilizzare i nodi normali, ma in un diverso spazio dei nomi XML -. Cioè

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

(dove myData è un alias xmlns per il namespace-uri)

In molti casi, i lettori stanno controllando solo per i dati in loro dello spazio dei nomi (o default / namespace vuoto) -. I valori in spazi dei nomi personalizzati sono generalmente ignorati

Per ottenere imballare l'XML originale, un approccio semplice sarebbe quello di correre attraverso un XSLT che rispetta solo lo spazio dei nomi di default / originale.


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

Per rimuovere tali dati da un XElement, forse:

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

Altri suggerimenti

La domanda originale ha usato la parola "Serialize", ma poi anche menzionato XElement e annotazione. Per me si tratta di due cose diverse.

Se davvero si vuole utilizzare il XmlSerializer:
Quello che vorrei fare è utilizzare XmlAttributeOverrides, per differenziare la serializzazione. Con i XmlAttributeOverrides di programmazione è possibile, in fase di esecuzione, ignorare gli attributi XML serializzazione che decorano i tipi di.

All'interno del vostro tipo, si può avere un campo / proprietà che è destinato a contenere l'annotazione / documentazione. Decorare che con XmlIgnore. Quindi, creare un'istanza del XmlSerializer che non accetta le sostituzioni. L'annotazione non verrà serializzato o de-serializzato. Creare un'altra istanza del XmlSerializer per quel tipo, utilizzando un oggetto XmlAttributeOverrides. Specificare un override per il XmlIgnore'd immobile (uso XmlElementAttribute), nonché le sostituzioni per eventuali attributi su uno qualsiasi degli altri componenti (uso XmlIgnore = true).

serializzare l'istanza per due volte, una con ogni serializzatore.


Edit: ecco il codice:

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

uscita, utilizzando la in-line attributi:

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

uscita, utilizzando il prevalgono sugli attributi:

<DTO-Annotations xmlns="urn:www.example.org">
  <note>This will bbe serialized separately</note>
</DTO-Annotations>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top