请原谅我不精通XML声明,以及从类和定义的角度来看必须做什么才能使序列化/反序列化工作。 我正在尝试反序列化以下 XML:
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Owner>
<ID>946a0786-3840-4007-afe1-76f138a3d31c</ID>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>946a0786-3840-4007-afe1-76f138a3d31c</ID>
</Grantee>
<Permission>FULL_CONTROL</Permission>
</Grant>
</AccessControlList>
</AccessControlPolicy>
引发以下异常:
The specified type was not recognized: name='CanonicalUser', namespace='http://s3.amazonaws.com/doc/2006-03-01/', at <Grantee xmlns='http://s3.amazonaws.com/doc/2006-03-01/'>.
我将代码简化为以下内容以单独重现:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace sandbox
{
public partial class Program
{
static void Main(string[] args)
{
string xml =
"<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>946a0786-3840-4007-afe1-76f138a3d31c</ID></Owner><AccessControlList><Grant><Grantee xsi:type="CanonicalUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ID>946a0786-3840-4007-afe1-76f138a3d31c</ID></Grantee><Permission>FULL_CONTROL</Permission></Grant><Grant><Grantee xsi:type="CanonicalUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ID>946a0786-3840-4007-afe1-76f138a3d31c</ID></Grantee><Permission>READ</Permission></Grant><Grant><Grantee xsi:type="CanonicalUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ID>946a0786-3840-4007-afe1-76f138a3d31c</ID></Grantee><Permission>WRITE</Permission></Grant><Grant><Grantee xsi:type="CanonicalUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ID>946a0786-3840-4007-afe1-76f138a3d31c</ID></Grantee><Permission>READ_ACP</Permission></Grant><Grant><Grantee xsi:type="CanonicalUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><ID>946a0786-3840-4007-afe1-76f138a3d31c</ID></Grantee><Permission>WRITE_ACP</Permission></Grant></AccessControlList></AccessControlPolicy>";
try
{
AccessControlPolicy acp = DeserializeXml<AccessControlPolicy>(xml);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
public static T DeserializeXml<T>(string xml)
{
XmlSerializer xmls = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
return (T)xmls.Deserialize(ms);
}
}
}
[XmlRoot(ElementName = "AccessControlPolicy", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public class AccessControlPolicy
{
[XmlElement(ElementName = "Owner", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public Owner Owner { get; set; }
[XmlElement(ElementName = "AccessControlList", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public AccessControlList AccessControlList { get; set; }
}
[XmlRoot(ElementName = "AccessControlList", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public class AccessControlList
{
[XmlElement(ElementName = "Grant", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public List<Grant> Grant { get; set; }
}
[XmlRoot(ElementName = "Grant", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public class Grant
{
[XmlElement(ElementName = "Grantee", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public Grantee Grantee { get; set; }
[XmlElement(ElementName = "Permission", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public string Permission { get; set; }
}
[XmlRoot(ElementName = "Grantee", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public class Grantee
{
[XmlElement(ElementName = "ID", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public string ID { get; set; }
[XmlElement(ElementName = "URI", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public string URI { get; set; }
[XmlElement(ElementName = "DisplayName", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public string DisplayName { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
}
[XmlRoot(ElementName = "Owner", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public class Owner
{
[XmlElement(ElementName = "ID", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public string ID { get; set; }
[XmlElement(ElementName = "DisplayName", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public string DisplayName { get; set; }
}
}
> XmlSerializer
使用 xsi:type
说明符解析反序列化的目标类。
由于目标class
被命名为 Grantee
因此您必须使用 XmlType
属性对其进行修饰,该属性将CanonicalUser
指定为 TypeName
。
[XmlType(TypeName= "CanonicalUser")]
public class Grantee
请注意,您可以减少应用于类的xml namespaces
,如下所示。
[XmlRoot(ElementName = "AccessControlPolicy", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")]
public class AccessControlPolicy
{
[XmlElement(ElementName = "Owner", IsNullable = true)]
public Owner Owner { get; set; }
[XmlElement(ElementName = "AccessControlList", IsNullable = true)]
public AccessControlList AccessControlList { get; set; }
}
public class AccessControlList
{
[XmlElement(ElementName = "Grant", IsNullable = true)]
public List<Grant> Grant { get; set; }
}
public class Grant
{
[XmlElement(ElementName = "Grantee", IsNullable = true)]
public Grantee Grantee { get; set; }
[XmlElement(ElementName = "Permission", IsNullable = true)]
public string Permission { get; set; }
}
[XmlType(TypeName= "CanonicalUser")]
public class Grantee
{
[XmlElement(ElementName = "ID", IsNullable = true)]
public string ID { get; set; }
[XmlElement(ElementName = "URI", IsNullable = true)]
public string URI { get; set; }
[XmlElement(ElementName = "DisplayName", IsNullable = true)]
public string DisplayName { get; set; }
}
public class Owner
{
[XmlElement(ElementName = "ID", IsNullable = true)]
public string ID { get; set; }
[XmlElement(ElementName = "DisplayName", IsNullable = true)]
public string DisplayName { get; set; }
}
更新
如果您想使用不同的xsi:type
说明符,例如。
<Grantee xsi:type="CanonicalUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Grantee xsi:type="AnotherUser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
然后,您必须为两者声明一个类,并具有一个公共基类。
必须使用涉及的每个具体派生类的XmlIncludeAttribute
来修饰基类。
必须对派生类应用XmlTypeAttribute
。
[XmlInclude(typeof(CanonicalUser))]
[XmlInclude(typeof(AnotherUser))]
public abstract class Grantee
{
// ...
}
[XmlType(TypeName= "CanonicalUser", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")]
public class CanonicalUser : Grantee
{}
[XmlType(TypeName = "AnotherUser", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/")]
public class AnotherUser : Grantee
{}
重命名您的类授予 CanonicalUser。
[XmlRoot(ElementName = "AccessControlList", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public class AccessControlList
{
[XmlElement(ElementName = "Grant", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public List<CanonicalUser> Grant { get; set; }
}
[XmlRoot(ElementName = "Grant", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public class CanonicalUser
{
[XmlElement(ElementName = "Grantee", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public Grantee Grantee { get; set; }
[XmlElement(ElementName = "Permission", Namespace = "http://s3.amazonaws.com/doc/2006-03-01/", IsNullable = true)]
public string Permission { get; set; }
}