Hay una manera de configurar el XmlSerializer para que no escriba espacios de nombres por defecto en el elemento raíz?

Lo que me sale es este:

<?xml ...>
<rootelement xmlns:xsi="..." xmlns:xsd="...">
</rootelement>

y quiero quitar tanto xmlns declaraciones.

Duplicado de: Cómo serializar un objeto XML sin llegar xmlns=»…»?

3 Comentarios

  1. 59

    Desde que Dave me pedía a repetir mi respuesta a Omitiendo todos los xsi y xsd espacios de nombres al serializar un objeto en .NET, he actualizado este post y repite mi respuesta a esta pregunta a partir de la mencionada enlace. En el ejemplo utilizado en esta respuesta es el mismo ejemplo utilizado para la otra pregunta. Lo que sigue es copiado textualmente.


    Después de leer la documentación de Microsoft y varias soluciones en línea, he descubierto la solución a este problema. Funciona tanto con la incorporada en el XmlSerializer y personalizado serialización XML a través de IXmlSerialiazble.

    Para ello, voy a utilizar el mismo MyTypeWithNamespaces XML de ejemplo que se ha utilizado en las respuestas a esta pregunta tan lejos.

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

    Eso es todo para esta clase. Ahora, algunos se opusieron a tener un XmlSerializerNamespaces objeto en algún lugar dentro de sus clases; pero como usted puede ver, yo prolijamente guardado en el constructor por defecto y se expone una propiedad pública para devolver los espacios de nombres.

    Ahora, cuando llega la hora de serializar la clase, se puede usar el siguiente código:

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

    Una vez hecho esto, usted debe obtener el siguiente resultado:

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

    He utilizado con éxito este método en un proyecto reciente, con un profundo jerarquía de clases que se serializa en XML para llamadas de servicio web. La documentación de Microsoft no es muy claro acerca de qué hacer con el público accesible XmlSerializerNamespaces miembro una vez que hayas creado, y muchos piensan que es inútil. Pero después de su documentación y su uso en el modo que se muestra arriba, usted puede personalizar la forma en que la clase XmlSerializer genera XML para sus clases sin tener que recurrir a los no admitidos comportamiento o «rodar su propio» serialización mediante la implementación de IXmlSerializable.

    Es mi esperanza que esta respuesta va a poner a descansar de una vez por todas, la manera de deshacerse de la norma xsi y xsd espacios de nombres generados por el XmlSerializer.

    ACTUALIZACIÓN: yo sólo quiero para asegurarse de que me contestó el OP pregunta acerca de la eliminación de todos los espacios de nombres. Mi código de trabajo para este; déjeme mostrarle cómo. Ahora, en el ejemplo anterior, usted realmente no puede deshacerse de todos los espacios de nombres (porque hay dos espacios de nombres en uso). En algún lugar en su documento de XML, usted va a necesitar para tener algo como xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo. Si la clase en el ejemplo es parte de un documento más grande, entonces en algún lugar por encima de un espacio de nombres debe ser declarada por uno (o ambos) Abracadbra y Whoohoo. Si no, entonces el elemento en uno o ambos de los espacios de nombres debe ser decorado con un prefijo de algún tipo (usted no puede tener dos espacios de nombres por defecto, ¿verdad?). Así, para este ejemplo, Abracadabra es el espacio de nombres predeterminado. Pude dentro de mi MyTypeWithNamespaces clase de añadir un prefijo de espacio de nombres para el Whoohoo espacio de nombres como:

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

    Ahora, en mi definición de la clase, me indicó que la <Label/> elemento está en el espacio de nombres "urn:Whoohoo", por lo que no necesita hacer nada más. Cuando ahora me serializar la clase utilizando mi código de serialización sin cambios, este es el resultado:

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

    Porque <Label> es en un espacio de nombres diferente del resto del documento, se debe, en alguna manera, ser «decorados» con un espacio de nombres. Aviso que todavía no hay xsi y xsd espacios de nombres.


    Esto termina mi respuesta a la otra pregunta. Pero yo quería asegurarme de que me respondió el OP pregunta sobre el no uso de espacios de nombres, como me siento yo en realidad no la dirección todavía. Suponga que <Label> es parte del mismo espacio de nombres que el resto del documento, en este caso urn:Abracadabra:

    <MyTypeWithNamespaces>
    <Label>myLabel<Label>
    <Epoch>42</Epoch>
    </MyTypeWithNamespaces>

    Su constructor sería como lo haría en mi primer ejemplo de código, junto con el público de la propiedad para recuperar el espacio de nombres predeterminado:

    //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[] {
    new XmlQualifiedName(string.Empty, "urn:Abracadabra") //Default Namespace
    });
    }
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces Namespaces
    {
    get { return this._namespaces; }
    }
    private XmlSerializerNamespaces _namespaces;

    Luego, más tarde, en el código que utiliza el MyTypeWithNamespaces objeto a serializar, se le llame como lo hice anteriormente:

    MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);
    XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
    new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });
    ...
    //Above, you'd setup your XmlTextWriter.
    //Now serialize our object.
    xs.Serialize(xtw, myType, myType.Namespaces);

    Y la XmlSerializer escupía vuelve a salir el mismo XML, como se muestra inmediatamente por encima sin espacios de nombres adicionales en la salida:

    <MyTypeWithNamespaces>
    <Label>myLabel<Label>
    <Epoch>42</Epoch>
    </MyTypeWithNamespaces>
    • Para su integridad, tal vez usted debería incluir la respuesta correcta en lugar de referirse simplemente a él, y también, estoy interesado en saber cómo llegar a la conclusión de que es «incompatible comportamiento’.
    • Bueno, así que aquí lo dice: msdn.microsoft.com/en-us/library/…
    • Dave, repetí mi respuesta para usted. También, quería asegurarme de que me dirigí a su pregunta original sobre espacios de nombres no aparecen. Si sólo tiene un espacio de nombres en el fragmento de XML/documento y agregó que el espacio de nombres predeterminado para un públicamente disponible XmlSerializerNamespaces colección dentro de su objeto con todos los elementos que pertenecen a ese espacio de nombres, a continuación, cuando se llama a la XmlSerializer como he mostrado anteriormente, no hay espacios de nombres sería de salida en el resultado serialzied XML. HTH.
    • Vino aquí de nuevo para comprobar esto, ya que es la más sencilla explicación que he encontrado. Gracias @fourpastmidnight
    • Me alegro de que podría ser de servicio a la comunidad!
    • No lo entiendo, para su OP final de la respuesta, usted todavía está utilizando un espacio de nombres durante la serialización «urn:Abracadabra» (constructor), ¿por qué es que no se incluye en el resultado final. No debería el OP de uso : XmlSerializerNamespaces EmptyXmlSerializerNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Vacío });
    • No está incluido en el resultado final porque es el espacio de nombres predeterminado, cada elemento se supone que pertenecen a ese espacio de nombres, a menos que se especifique otra cosa (por ejemplo, como un atributo en la clase de la serialización XML). Observe cómo XHTML declara su espacio de nombres predeterminado: xmlns=http://...., no xmlns:xhtml=..... Si esto fuera declarado de la segunda manera, sus páginas tendría que ser como <xhtml:html><xhtml:body>Your content</xhtml:body></xhtml:head>. Al especificar ningún nombre de espacio de nombres, no es necesario utilizar en la clasificación del elemento.
    • Hola @fourpastmidnight , es tu solución también se aplica a mi pregunta stackoverflow.com/questions/27325097/… ?
    • No estoy seguro de si esto iba a funcionar con WCF o no. WCF utiliza su propia serialización. Ahora, si vas a implementar su propio serializador, entonces, sí, esta solución debería funcionar igual de bien para usted. HTH.
    • Hola @fourpastmidnight, cualquier puntero no hay cómo implementar mi propio serializador y la uso en mi WCF. si puedes responder mi pregunta . realmente muy agradecido por las aconsejo
    • Lo siento, no vi esta respuesta antes. Sé que usted puede crear su propio WCF serializadores, pero no sé cómo hacerlo, en la parte superior de mi cabeza. Esperemos que haya encontrado la manera. Puedo tratar de echar un vistazo y ver la forma en que se llevaría a cabo en el ínterin.
    • He encontrado esto PARA Q&A que dice, sí, usted puede crear su propio WCF serializador y lo que usted necesita hacer para lograr eso. HTH.
    • Esta es la respuesta correcta, aunque no es el más votado. El onky cosa que no funcionó para mí fue XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws); he tenido que cambiar por var xtw = XmlTextWriter.Create(memStm, xws);.
    • pero entonces usted no tiene acceso a cosas como .El formato. Podría este problema se abordó también «correctamente», por favor?
    • Ha sido un tiempo desde que escribí esta respuesta. XmlTextWriter.Create devuelve un (abstracto?) XmlWriter instancia. Así que @Preza8 es correcto, iba a perder la capacidad para establecer otros XmlTextWriterpropiedades específicas (al menos, no sin abajo-colada), por lo tanto, el yeso específico para XmlTextWriter.

  2. 251
    //Create our own namespaces for the output
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    //Add an empty namespace and empty value
    ns.Add("", "");
    //Create the serializer
    XmlSerializer slz = new XmlSerializer(someType);
    //Serialize the object with our own namespaces (notice the overload)
    slz.Serialize(myXmlTextWriter, someObject, ns)
    • Exactamente. Funciona como un encanto.
    • Hmmm…ustedes son rebeldes. Explícitamente dice en msdn.microsoft.com/en-us/library/… que usted no puede hacer eso.
    • Bool Yah! (Para la superación de lo que ms dices no se puede hacer)
    • No estoy seguro de por qué es «incompatible», pero esto es exactamente lo que yo quería.
    • El enlace es redireccionar a otra parte…
    • Hola @Jeremy, ¿cómo puedo aplicar la solución de mi problema aquí stackoverflow.com/questions/27325097/… ?
    • Esta respuesta genera «xmlns:d1p1» y «xmlns:q1» espacios de nombres. ¿Qué es esto?
    • Yo upvoted sin darse cuenta de que no funciona. Me gustaría -1 este. d1p1:type="MyCustomType" xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance es lo que me pasa cuando uso este.
    • lamento que usted está teniendo un problema. Este post ha sido alrededor de un rato, así que sólo he probado el código y todavía funciona. Usted puede elaborar?
    • Bien, este código funciona para realmente muy simple serializations, sin otras definiciones de espacio de nombres. Para múltiples definiciones de espacio de nombres, el trabajo de respuesta es la aceptación de uno.
    • A lo mejor ha funcionado antes, pero me da la temida q1 en mi salida. Nunca he visto a nombre de los espacios generados en WCF [Datamember] tal vez debería utilizar en su lugar.

  3. 6

    Hay una alternativa – puede proporcionar a un miembro de tipo XmlSerializerNamespaces en el tipo de secuela. Decorar con el XmlNamespaceDeclarations atributo. Agregar los prefijos de espacio de nombres y URIs para ese miembro. Entonces, cualquier serialización que no establece de manera explícita una XmlSerializerNamespaces utilizará el prefijo de espacio de nombres+URI pares que han puesto en su tipo.

    Código de ejemplo, supongamos que este es tu tipo:

    [XmlRoot(Namespace = "urn:mycompany.2009")]
    public class Person {
    [XmlAttribute] 
    public bool Known;
    [XmlElement]
    public string Name;
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces xmlns;
    }

    Usted puede hacer esto:

    var p = new Person
    { 
    Name = "Charley",
    Known = false, 
    xmlns = new XmlSerializerNamespaces()
    }
    p.xmlns.Add("",""); //default namespace is emoty
    p.xmlns.Add("c", "urn:mycompany.2009");

    Y que significa que cualquier serialización de esa instancia y que no especifica su propio conjunto de prefijo+URI pares será el uso de la «p» de prefijo para el «urn:miempresa.2009» espacio de nombres. También se omite la xsi y xsd espacios de nombres.

    La diferencia aquí es que usted está agregando el XmlSerializerNamespaces el tipo en sí, en lugar de emplear de manera explícita en una llamada a la clase XmlSerializer.Serialize(). Esto significa que si una instancia del tipo de serie, código de usted (por ejemplo, en un webservices de la pila), y de que el código no establece de manera explícita un XmlSerializerNamespaces, que serializador hará uso de los espacios de nombres proporcionada en la instancia.

    • 1. Yo no veo la diferencia. Todavía estás a agregar el espacio de nombres predeterminado a una instancia de XmlSerializerNamespaces.
    • 2. Esto contamina las clases más. Mi objetivo no es el uso de ciertos nombres, mi objetivo no es utilizar espacios de nombres en todos.
    • He añadido una nota acerca de la diferencia entre este enfoque y el de la especificación de la XmlSerializerNamespaces durante la serialización sólo.

Dejar respuesta

Please enter your comment!
Please enter your name here