如何将.xml文件与xmlns-attributes一起反序列化?

时间:2011-05-23 06:55:00

标签: c# xml xml-namespaces xml-deserialization

我正在努力学习反序列化。我编写了这段代码来反序列化* .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 个答案:

答案 0 :(得分:3)

xmlns(xml名称空间)属性保留给XML。 XmlSerializer永远不会将它返回给你。

答案 1 :(得分:3)

只需使用NamespaceXmlRootXmlTypeXmlAttribute(等)上的XmlElement属性即可解决此问题。示例如下所示:

输出:

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

Xml(from here):

<?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值 - 但它应该表明它基本上有效。

答案 2 :(得分:1)

自.NET类型以来,序列化程序不知道XML命名空间 没有宣布它。

您需要添加以下属性以确保序列化程序 考虑命名空间:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:nhibernate-mapping-2.2")]
[System.Xml.Serialization.XmlRootAttribute("SupportedAgreementType", Namespace="urn:nhibernate-mapping-2.2", Nullable=false)]

答案 3 :(得分:0)

您可以使用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();
    }
}