为什么XmlReader将命名空间uris附加到每个元素?

时间:2010-03-04 12:08:30

标签: c# xml serialization xmlreader xmlserializer

我有一个包含以下格式的xml的Stream,我希望将其反序列化为C#对象

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<OrganisationMetaData xmlns="urn:organisationMetaDataSchema">
   <Organisations>
     <Organisation>
       <Code>XXX</Code>
       <Name>Yyyyyy</Name>...

我已经使用字符串完成了这么多次,但是对于流,它将命名空间属性附加到所有复杂元素。如果我只删除xmlns属性,并忘记根据模式验证它,它只是附加一个空的xmlns属性。我遇到的问题是XmlSerializer(?)中的Deserialize方法抛出一个错误,说它不期望该属性。我尝试使用XmlRoot和XmlType属性来修饰类,但这并没有改变任何内容。

这是我要反序列化的课程

[XmlRoot(
   ElementName = "OrganisationMetaData", 
   Namespace = "urn:organisationMetaDataSchema")]
public class OrganisationMetaData
{
    public List<Organisation> Organisations { get; set; }
}

[XmlType(
   TypeName = "Organisation", 
   Namespace = "urn:organisationMetaDataSchema")]
public class Organisation
{
   public string Code {get; set;}

   public string Name {get; set;}
}

以下是用于完成工作的方法

 public IList<Organisation> DeserializeOrganisations(Stream stream)
    {
        var serializer = new XmlSerializer(typeof(OrganisationMetaData));

        var mappingAssembly = //Resource in another assembly

        var schemas = new XmlSchemaSet();
        schemas.Add(
            "urn:organisationMetaDataSchema",
            XmlReader.Create(
                mappingAssembly.GetManifestResourceStream(
                    // An xml schema
                    )
                )
            );
        var settings = new XmlReaderSettings()
                           {
                               ValidationType = ValidationType.Schema,
                               Schemas = schemas,
                               ValidationFlags =
                     XmlSchemaValidationFlags.ReportValidationWarnings
                           };            

        settings.ValidationEventHandler += settings_ValidationEventHandler;
        var reader = XmlReader.Create(stream, settings);

        var metaData= (OrganisationMetaData)serializer.Deserialize(reader);
        return metaData.Organisations.ToList();
    }

我已经尝试过使用DataContractSerializer,但它带来了自己的学习机会,所以如果有人可以帮助我应该放置属性以使XmlSerializer工作,那就太好了。

任何帮助都将不胜感激,谢谢。

2 个答案:

答案 0 :(得分:1)

这里的关键是[XmlRoot]只能应用于根类型,例如类;如果您使用List<>作为根,它将无效 - 但我们可以使用[XmlElement]来填充它。我正在使用Stream方法(通过Encoding.UTF8),但请注意,这不是问题的核心IMO(根类型):

[XmlRoot(Namespace="urn:organisationMetaDataSchema")]
public class Organisations
{
    private readonly List<Organisation> items = new List<Organisation>();
    [XmlElement("Organisation")]
    public List<Organisation> Items { get { return items; } }

}
public class Organisation
{
    public string Code { get; set; }
    public string Name { get; set; }
}
static class Program
{
    static void Main()
    {
        string xml = @"<?xml version='1.0' encoding='utf-8' standalone='yes'?><Organisations xmlns='urn:organisationMetaDataSchema'><Organisation><Code>XXXX</Code><Name>YYYYYYYY</Name></Organisation></Organisations>";
        XmlSerializer ser = new XmlSerializer(typeof(Organisations));
        using (Stream input = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
        {
            Organisations orgs = (Organisations)ser.Deserialize(input);
        }
    }
}

答案 1 :(得分:0)

我最后更改了代码以使用数据协定序列化程序,它给了我更明显的命名空间错误,允许我有一个读取器根据模式验证xml流,然后回滚流并在另一个中再次使用它将xml反序列化的读者。

阅读this question提醒我一个问题,其中xml元素必须按字母顺序排列。我还发现当反序列化我的类的属性是一个枚举时,我需要要求它存在(它毕竟不可为空)。

这导致了另一个错误,其中我有一个xml节点,其中省略了一些值(我的架构确定),但是数据契约期望它们按顺序排列,所以我必须明确指定它。

我最终得到了像这样的数据成员属性

[DataMember(
        Name = "MyEnumType", 
        EmitDefaultValue = false, 
        IsRequired = true, 
        Order = 3)] 
//Just assume I added this prop after my Code, and Name properties from above

感谢Marc花时间看这个。