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

时间:2022-04-01 07:18:23

I am trying to learn deserialization. I have written this code to deserialize *.hbm.xml files.

我正在学习反序列化。我编写这段代码是为了反序列化*.hbm。xml文件。

Every element is loading correctly but "xmlns". The message in the exception is:

每个元素都正确加载,但是“xmlns”。例外的信息是:

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

What should be done to solve this?

我们应该做些什么来解决这个问题?

You want to see my complete code?

你想看看我的完整代码吗?

Here you go:

<?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 个解决方案

#1


3  

This is solved simply with the Namespace property on XmlRoot, XmlType, XmlAttribute and XmlElement (etc); example shown below:

这只需使用XmlRoot、XmlType、XmlAttribute和XmlElement(等等)上的名称空间属性即可解决;示例如下所示:

Output:

输出:

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

Xml (from here):

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#:

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();
    }
}

Note I've only mapped a few of the xml values - but it should show that it essentially works.

注意,我只映射了一些xml值——但它应该表明它实际上是有效的。

#2


3  

The xmlns (xml namespace) attribute is reserved to XML. The XmlSerializer will never return it to you class.

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

#3


1  

The serializer doesn't know about the XML namespace since the .NET Type doesn't declare it.

序列化器不知道XML名称空间,因为. net类型没有声明它。

You need to add the following attributes to make sure the serializer will consider the namespace:

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

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

#4


0  

Instead of trying to implement the deserialization automatically, you could use IXmlSerializable. It's really easy when you get used to it, and very flexible. You can instantiate readonly properties using the private backing instead of the public accessor, among other things. It's a little more verbose than attribute mapping, but here's some code you could use (I did things differently here and there to give you an idea of how things work):

与其尝试自动实现反序列化,不如使用IXmlSerializable。当你习惯它的时候,它真的很容易,而且非常灵活。您可以使用私有支持实例化readonly属性,而不是使用公共访问器。它比属性映射要复杂一些,但是这里有一些代码你可以使用(我在这里和那里做了不同的事情,让你了解事物是如何工作的):

[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();
    }
}

#1


3  

This is solved simply with the Namespace property on XmlRoot, XmlType, XmlAttribute and XmlElement (etc); example shown below:

这只需使用XmlRoot、XmlType、XmlAttribute和XmlElement(等等)上的名称空间属性即可解决;示例如下所示:

Output:

输出:

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

Xml (from here):

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#:

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();
    }
}

Note I've only mapped a few of the xml values - but it should show that it essentially works.

注意,我只映射了一些xml值——但它应该表明它实际上是有效的。

#2


3  

The xmlns (xml namespace) attribute is reserved to XML. The XmlSerializer will never return it to you class.

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

#3


1  

The serializer doesn't know about the XML namespace since the .NET Type doesn't declare it.

序列化器不知道XML名称空间,因为. net类型没有声明它。

You need to add the following attributes to make sure the serializer will consider the namespace:

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

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

#4


0  

Instead of trying to implement the deserialization automatically, you could use IXmlSerializable. It's really easy when you get used to it, and very flexible. You can instantiate readonly properties using the private backing instead of the public accessor, among other things. It's a little more verbose than attribute mapping, but here's some code you could use (I did things differently here and there to give you an idea of how things work):

与其尝试自动实现反序列化,不如使用IXmlSerializable。当你习惯它的时候,它真的很容易,而且非常灵活。您可以使用私有支持实例化readonly属性,而不是使用公共访问器。它比属性映射要复杂一些,但是这里有一些代码你可以使用(我在这里和那里做了不同的事情,让你了解事物是如何工作的):

[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();
    }
}