Как я могу десериализовать файлы .xml вместе с xmlns-атрибутами? - PullRequest
1 голос
/ 23 мая 2011

Я пытаюсь научиться десериализации. Я написал этот код для десериализации файлов * .hbm.xml.

Каждый элемент загружается правильно, кроме "xmlns". Сообщение в исключении:

<hibernate-mapping xmlns='urn:nhibernate-mapping-2.2'> was not expected.

Что нужно сделать, чтобы решить эту проблему?

Вы хотите увидеть мой полный код?

Вот, пожалуйста:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping
assembly="Sample.CustomerService.Domain" namespace="Sample.CustomerService.Domain"
>
  <class name="MyTable" table="MyTable" lazy="true" >
    <id name="ID">
      <generator class="identity" />
      <column name="ID" sql-type="int" not-null="true" />
    </id>
    <property name="Name">
      <column name="Name" sql-type="varchar" not-null="false" />
    </property>
    <property name="MfgDate">
      <column name="MfgDate" sql-type="datetime" not-null="true" />
    </property>
  </class>
</hibernate-mapping>
public class Class
    {
        [XmlAttribute("name")]
        public string Name { get; set; }

        [XmlAttribute("table")]
        public string Table { get; set; }

        [XmlAttribute("lazy")]
        public bool Lazy { get; set; }

        [XmlElement("id")]
        public Id Id { get; set; }

        [XmlElement("property")]
        public Property [] Properties { get; set; }
    }

 public class Column
    {
        [XmlAttribute("name")]
        public string ColumnName { get; set; }

        [XmlAttribute("sql-type")]
        public string SqlTypeName { get; set; }

        [XmlAttribute("not-null")]
        public bool NotNull { get; set; }
    }

public class Generator
    {
        [XmlAttribute("class")]
        public string Class { get; set; }
    }

[XmlRoot("hibernate-mapping", Namespace = "urn:nhibernate-mapping-2.2")]
    public class HibernateMapping
    {
        [XmlAttribute("assembly")]
        public string AssemblyName { get; set; }

        [XmlAttribute("namespace")]
        public string NamespaceName { get; set; }

        [XmlElement("class")]
        public Class Class { get; set; }

        public override string  ToString()
        {
            StringBuilder sb = new StringBuilder(NamespaceName);
            sb.Append(".");
            sb.Append(Class.Name);

            return sb.ToString();
        }
    }

public class Id
    {
        [XmlElement("generator")]
        public Generator Generator { get; set; }

        [XmlElement("column")]
        public Column Column { get; set; }
    }

public class Property
    {
        [XmlAttribute("name")]
        public string Name { get; set; }

        [XmlAttribute("column")]
        public string Column { get; set; }

        [XmlAttribute("type")]
        public string SqlTypeName { get; set; }

        [XmlAttribute("not-null")]
        public bool NotNull { get; set; }

        [XmlElement("column")]
        public Column PropColumn { get; set; }

        public string GetColumnName()
        {
            if (PropColumn != null)
            {
                return PropColumn.ColumnName;
            }
            else
            {
                return Name;
            }
        }

        public string GetSqlTypeName()
        {
            if (PropColumn != null)
            {
                return PropColumn.SqlTypeName;
            }
            else
            {
                return SqlTypeName;
            }
        }

        public bool GetNotNull()
        {
            if (PropColumn != null)
            {
                return PropColumn.NotNull;
            }
            else
            {
                return NotNull;
            }
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            //IList<HibernateMapping> list = HbmReader.Get("How_To_Deserialize_a_Hbm_File");
//            string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
//<hibernate-mapping xmlns=""urn:nhibernate-mapping-2.2"">
//    <class name=""Example.Library.Resources.TestObject, Example.Library"" table=""test_object"" lazy=""false"">
//        <id name=""TestId"" column=""TestId"" type=""Guid""> 
//            <generator class=""assigned"" /> 
//        </id> 
//        <property name=""Name"" type=""String"" length=""45"" />
//    </class>
//</hibernate-mapping>";

            Assembly assembly = Assembly.Load("Sample.CustomerService.Domain");
            string[] manifestResourceNames = assembly.GetManifestResourceNames();

            XmlSerializer ser = new XmlSerializer(typeof(HibernateMapping));

            Stream stream = assembly.GetManifestResourceStream(manifestResourceNames[0]);

            HibernateMapping obj = (HibernateMapping)ser.Deserialize(new StreamReader(stream));

            Console.WriteLine(obj.Class.Name);
            Console.WriteLine(obj.Class.Table);
            foreach (var prop in obj.Class.Properties)
            {
                Console.WriteLine("prop: " + prop.Name);
            }

            string str = string.Empty;
        }
    }

Ответы [ 4 ]

3 голосов
/ 17 ноября 2011

Это решается просто с помощью свойства Namespace в XmlRoot, XmlType, XmlAttribute и XmlElement (и т. Д.);Пример, показанный ниже:

Выход:

Example.Library.Resources.TestObject, Example.Library
test_object
prop: Name

Xml ( отсюда ):

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="Example.Library.Resources.TestObject, Example.Library" table="test_object" lazy="false">
        <id name="TestId" column="TestId" type="Guid"> 
            <generator class="assigned" /> 
        </id> 
        <property name="Name" type="String" length="45" />
    </class>
</hibernate-mapping>

C #:

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

[XmlRoot("hibernate-mapping", Namespace = "urn:nhibernate-mapping-2.2")]
public class HibernateMapping
{
    [XmlAttribute("assembly")]
    public string AssemblyName { get; set; }

    [XmlElement("class")] // should this be a list?
    public Class Class { get; set; }
}

public class Class
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlAttribute("table")]
    public string Table { get; set; }

    private readonly List<Property> properties = new List<Property>();
    [XmlElement("property")]
    public List<Property> Properties { get { return properties; } }
}
public class Property
{
    [XmlAttribute("name")]
    public string Name { get; set; }
}
static class Program
{
    static void Main()
    {
        File.WriteAllText("my.xml",
                          @"<?xml version=""1.0"" encoding=""utf-8"" ?>
<hibernate-mapping xmlns=""urn:nhibernate-mapping-2.2"">
    <class name=""Example.Library.Resources.TestObject, Example.Library"" table=""test_object"" lazy=""false"">
        <id name=""TestId"" column=""TestId"" type=""Guid""> 
            <generator class=""assigned"" /> 
        </id> 
        <property name=""Name"" type=""String"" length=""45"" />
    </class>
</hibernate-mapping>");


        var ser = new XmlSerializer(typeof(HibernateMapping));
        var obj = (HibernateMapping)ser.Deserialize(new StreamReader("my.xml"));
        Console.WriteLine(obj.Class.Name);
        Console.WriteLine(obj.Class.Table);
        foreach (var prop in obj.Class.Properties)
        {
            Console.WriteLine("prop: " + prop.Name);
        }
        Console.ReadKey();
    }
}

Обратите внимание, что я сопоставил только несколько значений xml, но это должно показать, что это по существу работает.

3 голосов
/ 23 мая 2011

Атрибут xmlns (пространство имен xml) зарезервирован для XML.XmlSerializer никогда не вернет его классу.

1 голос
/ 23 мая 2011

Сериализатор не знает о пространстве имен XML со времени .NET Type не объявляет это.

Вам необходимо добавить следующие атрибуты, чтобы убедиться, что сериализатор будет рассмотрим пространство имен:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")]
[System.Xml.Serialization.XmlRootAttribute("SupportedAgreementType", Namespace="urn:nhibernate-mapping-2.2", Nullable=false)]
0 голосов
/ 17 ноября 2011

Вместо автоматической реализации десериализации вы можете использовать IXmlSerializable. Это действительно легко, когда ты привыкаешь к этому, и очень гибкий. Вы можете создавать экземпляры свойств только для чтения, используя, помимо прочего, закрытую поддержку вместо открытого средства доступа. Это немного более многословно, чем отображение атрибутов, но вот некоторый код, который вы могли бы использовать (я кое-что делал здесь и там, чтобы дать вам представление о том, как все это работает):

[Serializable(), XmlRoot("hibernate-mapping", Namespace = "urn:nhibernate-mapping-2.2")]
public class HibernateMapping : IXmlSerializable
{
    public string AssemblyName { get; set; }
    public string NamespaceName { get; set; }
    public Class Class { get; set; }
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder(NamespaceName);
        sb.Append(".");
        sb.Append(Class.Name);
        return sb.ToString();
    }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        AssemblyName = reader["assembly"];
        NamespaceName = reader["namespace"];

        XmlSerializer classSerializer = new XmlSerializer(typeof(Class));

        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.LocalName)
                {
                    case "class":
                        Class = (Class)classSerializer.Deserialize(reader.ReadSubtree());
                        break;
                }
            }
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        throw new NotImplementedException();
    }
}

public class Column
{
    public string ColumnName { get; set; }
    public string SqlTypeName { get; set; }
    public bool NotNull { get; set; }
}

public class Generator
{
    public string Class { get; set; }
}

public class Id
{
    public Generator Generator { get; set; }
    public Column Column { get; set; }
}

public class Property
{
    public string Name { get; set; }
    public string Column { get; set; }
    public string SqlTypeName { get; set; }
    public bool NotNull { get; set; }
    public Column PropColumn { get; set; }
    public string GetColumnName()
    {
        if (PropColumn != null) { return PropColumn.ColumnName; }
        else { return Name; }
    }
    public string GetSqlTypeName()
    {
        if (PropColumn != null) { return PropColumn.SqlTypeName; }
        else { return SqlTypeName; }
    }
    public bool GetNotNull()
    {
        if (PropColumn != null) { return PropColumn.NotNull; }
        else { return NotNull; }
    }
}

[Serializable(), XmlRoot("class")]
public class Class : IXmlSerializable
{
    public string Name { get; set; }
    public string Table { get; set; }
    public bool Lazy { get; set; }
    public Id Id { get; set; }
    public Property[] Properties { get; set; }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        Name = reader["name"];
        Table = reader["table"];
        Lazy = Convert.ToBoolean(reader["lazy"]);

        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.LocalName)
                {
                    case "id":
                        ReadIdXml(reader.ReadSubtree());
                        break;
                    case "property":
                        ReadPropertyXml(reader.ReadSubtree());
                        break;
                }
            }
        }
    }

    private void ReadIdXml(XmlReader reader)
    {
        //you can read the attributes and subnodes of the id node as above...
        Id = new Id();

        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.LocalName)
                {
                    case "generator":
                        Id.Generator = new Generator();
                        Id.Generator.Class = reader["class"];
                        break;
                    case "column":
                        Id.Column = ReadColumnXml(reader.ReadSubtree());
                        break;
                }
            }
        }
    }

    private void ReadPropertyXml(XmlReader reader)
    {
        Property property = new Property();
        property.Name = reader["name"];

        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.LocalName)
                {
                    case "generator":
                        property.PropColumn = ReadColumnXml(reader.ReadSubtree());
                        break;
                }
            }
        }

    }

    private Column ReadColumnXml(XmlReader reader)
    {
        Column column = new Column();
        column.ColumnName = reader["name"];
        column.SqlTypeName = reader["sql-type"];
        column.NotNull = Convert.ToBoolean(reader["non-null"]);
        return column;
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        throw new NotImplementedException();
    }
}
...