Pregunta

Tengo una situación en la que tengo un archivo XML que no quiero modificar. La función AddAnnotation en clase XElement proporciona una opción para añadir datos de memoria de sólo que no es serializado y no forma parte del XML.

Quiero ser capaz de salvar estas anotaciones (por ejemplo: en otro archivo XML) y luego deserializar tanto el xml y las anotaciones con el fin de conseguir el mismo objeto que tenía.

No quiero cambiar el XML original y esa es la razón por la que yo uso anotaciones.

Para resumir, quiero ser capaz de añadir datos personalizados a un archivo XML. Estos datos no será una parte del xml cuando serializarlo o será una parte del xml pero yo sería capaz de recuperar el XML original con facilidad.

¿Tiene alguna recomendación cómo puedo hacer tal cosa?

Editar ¿Debo usar instrucciones de procesamiento XML? Procesando instrucciones destinado para este tipo de uso?

¿Fue útil?

Solución

Me suena como el enfoque más simple sería utilizar nodos regulares, pero en un espacio de nombres XML diferente -. Es decir

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

(donde myData es un alias xmlns para el espacio de nombres-uri)

En muchos casos, los lectores son de sólo la comprobación de los datos en su de espacio de nombres (o el valor por defecto / espacio de nombres en blanco) -. Los valores en espacios de nombres personalizados están generalmente omiten

Para obtener empacar el XML original, un enfoque simple sería que se ejecutan a través de un XSLT que sólo respeta el / espacio de nombres de original predeterminado.


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

Para eliminar tales datos de un XElement, tal vez:

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

Otros consejos

La pregunta original usó la palabra "Serialize", pero luego también mencionó XElement y anotación. Para mí se trata de dos cosas diferentes.

Si realmente desea utilizar XmlSerializer:
Lo que me gustaría hacer es utilizar XmlAttributeOverrides, para diferenciar la serialización. Con los XmlAttributeOverrides puede mediante programación, en tiempo de ejecución, anular los atributos de serialización XML que decoran sus tipos.

Dentro de su tipo, puede tener un campo / propiedad que está destinado a contener la anotación / documentación. Decorar con que XmlIgnore. A continuación, cree una instancia de la clase XmlSerializer que no acepta las anulaciones. La anotación no será serializado o serializado DE. Crear otra instancia de la XmlSerializer para ese tipo, utilizando un objeto XmlAttributeOverrides. Especificar un reemplazo para la propiedad XmlIgnore'd (uso XmlElementAttribute), así como las anulaciones para cualquier atributo en cualquiera de los otros miembros (uso XmlIgnore = true).

serializar el ejemplo dos veces, una con cada serializador.


Edit: aquí está el código:

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

salida, utilizando la línea en los atributos:

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

salida, utilizando la anulación atributos:

<DTO-Annotations xmlns="urn:www.example.org">
  <note>This will bbe serialized separately</note>
</DTO-Annotations>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top