如何使用 XmlSerializer 属性分析此 XML

本文关键字:XML 属性 何使用 XmlSerializer | 更新日期: 2023-09-27 18:21:35

我们需要使用一个"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 序列化程序属性或需要尽可能少的样板代码的任何其他方式。

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

我当然可以在这些类中手动实现IXmlSerializable,或者只是制作FooBar类并将其与XmlSerializer一起使用,但这些选项似乎都不是一个好的解决方案。

提前感谢您的回答!

如何使用 XmlSerializer 属性分析此 XML

你不能用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>

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

由于您在评论中说,为了简单起见,您正在为 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,这允许人们确保类不变量和/或使对象不可变。

对于要反序列化为相同

类型项目的大型系列(或仅包含几种类型的大型系列(的大型文档,此方法会发挥作用,因为可以在创建它们时将它们yield出来,这可能会对第一次响应的延迟产生相当大的影响。

您可以尝试"XML 架构定义工具"(http://msdn.microsoft.com/de-de/library/x6c1kb0s%28v=vs.80%29.aspx (

再见! 斯特凡