如何使用XmlSerializer属性解析此XML?

时间:2012-01-26 17:31:16

标签: c# .net xml-serialization xmlserializer

我们需要使用“Web服务”来传达非常丑陋的XML。它不是由我们开发的,也没有机会让开发人员理解正确的XML。

仅供参考,这个Web服务也接受HTTP GET URL参数(而不是请求体)中的相同类型的XML - 开发它的人不明白为什么这是一个不好的做法。

那么,映射XML的最快方法是什么:

<foo id="document">
    <foo id="customer">
        <bar name="firstname" value="Joe"/>
        <bar name="lastname" value="Smith"/>
        <foo id="address">
            <bar name="city" value="New York"/>
            <bar name="country" value="USA"/>
        </foo>
    </foo>
    <bar name="somemoredata1" value="123"/>
    <bar name="somemoredata2" value="abc"/>
</foo>

进入这样的课程:

public class Document
{
    public Customer Customer { get; set; }

    public int SomeMoreData1 { get; set; }

    public string SomeMoreData2 { get; set; }
}

public class Customer
{
    public Address Address { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
}


public class Address
{
    public string City { get; set; }

    public string Country { get; set; }
}

使用例如。 XML Serializer属性或需要尽可能少的样板代码的任何其他方式。

我编写了foobar元素名称,但我需要解析的XML结构基于完全相同的约定。

我当然可以在这些类中手动实现IXmlSerializable,或者只创建FooBar类并使用XmlSerializer类,但这些选项似乎都没有是一个很好的解决方案。

提前感谢您的回答!

4 个答案:

答案 0 :(得分:1)

我自己没有使用xml序列化程序或反序列化程序,但我确实使用LINQ将我的XML文档解析为对象。如果您的课程相当简单,您可以查看该路线。

答案 1 :(得分:1)

您无法使用XML序列化程序属性执行此操作:无法使其从指定的属性中获取字段名称。您将不得不手动反序列化(可能生成样板)或预处理XML - 沿着以下行的简单XSLT将起到作用:

<xsl:template match="foo">
  <xsl:element name="{@id}">
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="bar">
  <xsl:element name="{@name}">
    <xsl:value-of select="@value"/>
  </xsl:element>
</xsl:template>
反向转换的

更新:

<xsl:template match="*[count(child::text())=1]">
  <bar value="{text()}" name="{local-name()}"/>
</xsl:template>

<xsl:template match="*">
  <foo id="{local-name()}">
    <xsl:apply-templates/>
  </foo>
</xsl:template>

答案 2 :(得分:1)

因为你在评论中说为了简单而你是为了XmlSerializer而不是因为这种方法是由其他问题强制执行的,所以这是一种不同的方法。由于在文档中似乎元素的名称无关紧要,我在解析中忽略它,尽管也可以测试它。使用更令人愉快的XML格式,这将是解析关键的主要因素(通常在元素名称上使用switch):

private static Document ParseDocument(XmlReader xr)
{
    Document doc = new Document();
    while(xr.Read())
      if(xr.NodeType == XmlNodeType.Element)
        if(xr.GetAttribute("id") == "customer")
          doc.Customer = ParseCustomer(xr.ReadSubtree());
        else
          switch(xr.GetAttribute("name"))
          {
            case "somemoredata1":
              doc.SomeMoreData1 = int.Parse(xr.GetAttribute("value"));
              break;
            case "somemoredata2":
              doc.SomeMoreData2 = xr.GetAttribute("value");
              break;
          }
      //Put some validation of doc here if necessary.
      return doc;
}
private static Customer ParseCustomer(XmlReader xr)
{
  Customer cu = new Customer();
  while(xr.Read())
    if(xr.NodeType == XmlNodeType.Element)
      if(xr.GetAttribute("id") == "address")
        cu.Address = ParseAddress(xr.ReadSubtree());
      else
        switch(xr.GetAttribute("name"))
        {
          case "firstname":
            cu.FirstName = xr.GetAttribute("value");
            break;
          case "lastname":
            cu.LastName = xr.GetAttribute("value");
            break;
        }
    //validate here if necessary.
    return cu;
}
private static Address ParseAddress(XmlReader xr)
{
  Address add = new Address();
  while(xr.Read())
    if(xr.NodeType == XmlNodeType.Element)
      switch(xr.GetAttribute("name"))
      {
        case "city":
          add.City = xr.GetAttribute("value");
          break;
        case "country":
          add.Country = xr.GetAttribute("value");
          break;
      }
  return add;
}

它并不完全漂亮(使用漂亮的XML并不是非常漂亮,但它往往不会那么糟糕),但它可以工作,并且使用子树可以很好地使用相同类型的一些复杂结构可以在文档中的不同位置出现。可以使用带有XmlReader的contstructors来替换从外部设置值的静态方法,该yield允许确保类不变量,和/或使对象不可变。

这种方法在大型文档的情况下自成一体,您希望将其作为一系列相同类型的项目(或大量系列的几种类型)进行反序列化,因为可以{{1}}它们在创建时出来,这对于第一次响应的延迟会产生很大影响。

答案 3 :(得分:-1)

您可以尝试“XML Schema Definition-Tool”(http://msdn.microsoft.com/de-de/library/x6c1kb0s%28v=vs.80%29.aspx

侨!   斯蒂芬