2009-02-26 9 views
14

Si tengo una clase marcada como un DataContract y algunas propiedades en ella marcados con DataMember atributos Puedo serializar a XML con facilidad, pero sería crear una salida como:¿Cómo se puede controlar la serialización .NET DataContract para que use atributos XML en lugar de elementos?

<Person> 
    <Name>John Smith</Name> 
    <Email>[email protected]</Email> 
    <Phone>123-123-1234</Phone> 
</Person> 

Lo que yo prefiero es atributos , como ...

<Person Name="John Smith" Email="[email protected]" Phone="123-123-1234" /> 

el atributo DataMember me permite controlar el Nombre y la Orden, pero no si se serializa como un elemento o atributo. He mirado alrededor y encontré DataContractFormat y IXmlSerializable, pero espero que haya una solución más fácil.

¿Cuál es la manera más fácil de hacer esto?

+0

Además, necesito que el XML funcione de esta manera mientras JSON continúa funcionando. – Brennan

Respuesta

11

No puede hacer esto con el DataContractSerializer; si quiere atributos, necesita usar el XmlSerializer en su lugar. Con la clase DataContractSerializer, se permite un subconjunto más restrictivo de la especificación XML, que mejora el rendimiento y mejora la interoperabilidad de los servicios publicados, pero le otorga un control bastante menor sobre el formato XML.

Si está utilizando servicios WCF, eche un vistazo a XmlSerializerFormatAttribute que le permite usar el XmlSerializer para la serialización.

+1

Tiene que haber una manera simple de hacerlo usar atributos. No me importan los servicios web, solo para generar el XML en un formato específico. – Brennan

+0

Hola, me temo que Greg está en lo cierto; consulte http://msdn.microsoft.com/en-us/library/ms731923.aspx para conocer las limitaciones de DataContractSerializer. – larsw

+1

Si no le importan los servicios web, ¿por qué está usando WCF? ¿Estás tratando de serializar algunas clases? Si es así, entonces use el XmlSerializer por sí mismo. –

34

Usted puede hacer esto con el DataContractSerializer - la respuesta es a hacerse cargo de la serialización XML a sí mismo mediante la implementación de la interfaz IXmlSerializable . Para de sólo escritura de apoyo - puede dejar el implementación de ReadXml vacío, y nulo cambio de GetSchema, y ​​luego escribir la implementación de WriteXml de la siguiente manera:

public class MyPerson : IXmlSerializable 
{ 
    public string Name { get; set;} 
    public string Email { get; set;} 
    public string Phone { get; set;} 

    public XmlSchema GetSchema() { return null; } 
    public void ReadXml(XmlReader reader) { } 
    public void WriteXml(XmlWriter writer) 
    { 
    writer.WriteAttributeString("name", Name); 
    writer.WriteAttributeString("email", Email); 
    writer.WriteAttributeString("phone", Phone); 
    } 
} 

Si está utilizando la misma escriba para, por ejemplo, serialización JSON, y luego todavía puede agregar los atributos DataContract y DataMember; el DataContractSerializer utilizará la implementación de la interfaz IXmlSerializable solo cuando escriba Xml.

He escrito sobre este here.

+0

¿Está seguro de que el 'DataContractSerializer' invocará el método' WriteXml' de este código? –

+1

Lo sé, parece poco probable, pero acabo de publicar un artículo en nuestro blog corporativo en http: //www.labs.jobserve.com/Articles.aspx/Building-Labs - Writing-an-OpenSearch-Suggestions-provider-in-C-with-WCF donde puede descargar el código fuente que lo muestra en acción (usándolo para implementar sugerencias de OpenSearch). La pista proviene de este contenido de MSDN: http://msdn.microsoft.com/en-us/library/ms731923.aspx. –

+0

Además, asegúrese de ver http://msdn.microsoft.com/en-us/library/aa347876.aspx. –

0

Puede convertir de ida y vuelta entre atributos y elementos al serializar/deserializar. Los siguientes trabajos para este último.

private XmlReader AttributesToElements(Stream stream) 
    { 
      var root = XElement.Load(stream); 
      foreach (var element in root.Descendants()) { 
        foreach (var attribute in element.Attributes()) 
          element.Add(new XElement(root.Name.Namespace + attribute.Name.LocalName, (string)attribute)); 
        element.Attributes().Remove(); 
      } 
      return root.CreateReader(); 
    } 
Cuestiones relacionadas