XML 从属性到属性的反序列化

XML Deserialization from attributes to properties

如何像这样反序列化 xml:

<query>
  <parameters>
    <param name="lastUpdate">2012-05-25</param>
    <param name="code">11222122</param>
    <param name="type">idnLookup</param>
  </parameters>
  <response>
    <category name="person" version="1">
      <field name="surname">Soap</field>
      <field name="name1">Joe</field>
      <field name="date_of_birth">1973-05-09</field>
    </category>
    <category name="contact" version="1">
      <row>
        <field name="phone">0118063433</field>
        <field name="type">home</field>
        <field name="date">2003-01-01</field>
      </row>
      <row>
        <field name="phone">0124666566</field>
        <field name="type">home</field>
        <field name="date">2008-03-11</field>
      </row>
   </category>
  </response>
</query>

变成这样的 class 结构:

public class Query{
 public string lastUpdate {get;set;}
 public string code {get;set;}
 public string type {get;set;}
 public Response response {get;set;}
}
class Response{
  public Person person {get;set;}
  public Contact[] contacts {get;set;}
}
class Person {
  public string surname {get;set;}
  public string name1 {get;set;}
  public string date_of_birth {get;set;}
}
class Contact {
  public string phone {get;set;}
  public string type {get;set;}
  public string date {get;set;}
}

使用标准的 .net xml 序列化程序。还是我需要自己动手?

要扩展 Simon 的 xslt 想法,请考虑以下 xslt:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="/query/parameters">
    <xsl:apply-templates select="*"/>
    <!-- removes a level from the hierarchy by applying directly -->
  </xsl:template>
  <xsl:template match="*[@name]">
    <xsl:element name="{@name}">
      <xsl:apply-templates select="@*[name()!='name'] | * | text()"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

此处的关键匹配项是 *[@name],它采用以下任何形式:

<foo name="abc" ...>...</foo>

并将其重写为:

<abc ...>...</abc>

这会将您的 xml 转换为:

<query>
  <lastUpdate>2012-05-25</lastUpdate>
  <code>11222122</code>
  <type>idnLookup</type>
  <response>
    <person version="1">
      <surname>Soap</surname>
      <name1>Joe</name1>
      <date_of_birth>1973-05-09</date_of_birth>
    </person>
    <contact version="1">
      <row>
        <phone>0118063433</phone>
        <type>home</type>
        <date>2003-01-01</date>
      </row>
      <row>
        <phone>0124666566</phone>
        <type>home</type>
        <date>2008-03-11</date>
      </row>
    </contact>
  </response>
</query>

可以通过非常小的调整将其映射到您的模型作为属性:

[XmlRoot("query")] // <==== add this
public class Query {...}

[XmlArray("contact"), XmlArrayItem("row")] // <=== add this
public Contact[] contacts { get; set; }

可以使用哪个,例如:

static void Main()
{
    XslCompiledTransform xslt = new XslCompiledTransform();
    xslt.Load("my.xslt");
    var sw = new StringWriter();
    xslt.Transform("my.xml", null, sw);
    var transformedXml = sw.ToString();

    Console.WriteLine(transformedXml);
    Query query;
    using (var reader = XmlReader.Create(new StringReader(transformedXml)))
    {
        query = (Query)new XmlSerializer(typeof(Query)).Deserialize(reader);
    }
    // query is now fully populated
}

试试这个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication32
{
    class Program
    {
        const string FILENAME = @"c:\temp\Test.xml";
        static void Main(string[] args)
        {
            XmlSerializer xs = new XmlSerializer(typeof(Query));
            XmlTextReader reader = new XmlTextReader(FILENAME);
            Query query = (Query)xs.Deserialize(reader);
            query.Response.GetContacts();

        }
    }
    [XmlRoot("query")]
    public class Query
    {
        [XmlElement("parameters")]
        public Parameters Parameters {get;set;}
        [XmlElement("response")]
        public Response Response {get;set;}
    }
    [XmlRoot("parameters")]
    public class Parameters{
        private string lastUpdate {get;set;}
        private string code {get;set;}
        private string type {get;set;}

        [XmlElement("param")]
        public List<Param> m_params {get; set;}

    }
    [XmlRoot("param")]
    public class Param
    {
        [XmlAttribute("name")]
        public string name {get; set;} 
    }

    [XmlRoot("response")]
    public class Response
    {
      private Person person {get;set;}
      private List<Contact> contacts = new List<Contact>();
      [XmlElement("category")]
      public List<Category> categories {get;set;}

      public void GetContacts()
      {
          foreach (Category category in categories)
          {
              string catName = category.name;
              switch (catName)
              {
                  case "person" :
                      person = new Person();
                      foreach (Field field in category.fields)
                      {
                          switch (field.name)
                          {
                              case "surname" :
                                  person.surname = field.value;
                                  break;
                              case "name1":
                                  person.name1 = field.value;
                                  break;
                              case "date_of_birth":
                                  person.date_of_birth = field.value;
                                  break;
                              default :
                                  break;
                          }
                      }
                      break;
                  case "contact" :
                      foreach (Row row in category.row)
                      {
                          Contact newContact = new Contact();
                          contacts.Add(newContact);

                          foreach (Field field in row.fields)
                          {
                              switch (field.name)
                              {
                                  case "phone":
                                      newContact.phone = field.value;
                                      break;
                                  case "type":
                                      newContact.type = field.value;
                                      break;
                                  case "date":
                                      newContact.date = field.value;
                                      break;
                                  default:
                                      break;
                              }
                          }
                      }
                      break;
              }
          }
      }
    }
    [XmlRoot("category")]
    public class Category
    {
        [XmlAttribute("name")]
        public string name {get; set;}
        [XmlAttribute("version")]
        public string version { get; set; }
        [XmlElement("field")]
        public List<Field> fields {get; set;}
        [XmlElement("row")]
        public List<Row> row {get;set;}
    }
    [XmlRoot("row")]
    public class Row
    {
        [XmlElement("field")]
        public List<Field> fields {get; set;}
    }

    [XmlRoot("field")]
    public class Field
    {
        [XmlAttribute("name")]
        public string name { get; set; }
        [XmlText]
        public string value { get; set; }
    }

    class Person {
      public string surname {get;set;}
      public string name1 {get;set;}
      public string date_of_birth {get;set;}
    }
    class Contact {
      public string phone {get;set;}
      public string type {get;set;}
      public string date {get;set;}
    }
}