Почему XmlReader добавляет Uris пространства имен к каждому элементу? - PullRequest
1 голос
/ 04 марта 2010

У меня есть поток, содержащий xml в следующем формате, который я хочу десериализовать в объекты C #

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

Я делал это много раз со строками, но в потоке он любезно добавляет атрибут пространства имен ко всем сложным элементам. Если я просто удаляю атрибут xmlns и забываю проверить его по схеме, он просто добавляет пустой атрибут xmlns. У меня проблема в том, что метод Deserialize в XmlSerializer (?) Выдает ошибку, говоря, что не ожидает атрибут. Я попытался украсить класс атрибутами 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 ]

1 голос
/ 04 марта 2010

Ключевым моментом здесь является то, что [XmlRoot] может применяться только к корневому типу, такому как класс; если вы используете List<> в качестве корня, он не будет работать, но мы можем изменить это с помощью [XmlElement]. Я использую подход Stream (через Encoding.UTF8), но учтите, что на самом деле проблема не в IMO (тип root):

[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);
        }
    }
}
0 голосов
/ 09 марта 2010

Я закончил тем, что изменил код для использования сериализатора контракта данных, он дал мне более очевидные ошибки в пространстве имен, которые позволили мне иметь читатель, который проверял поток xml по схеме, а затем перематывал поток и использовал его снова в другом читатель, который десериализовал XML.

Чтение этот вопрос предупредил меня о том, что элементы 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

Спасибо Марку, что нашли время посмотреть на это.

...