【问题标题】:How to deserialize a class decorated with an XmlRoot namespace, when the XML has no namespace?当 XML 没有命名空间时,如何反序列化用 XmlRoot 命名空间装饰的类?
【发布时间】:2012-04-13 09:40:34
【问题描述】:

以前有人问过这个问题,但答案对我不起作用:所以这里又是一个问题:)

我在尝试反序列化某些 XML 时遇到了很大的麻烦,希望有人能提供一些帮助。我已经阅读了很多类似的帖子,但我无法解决这个问题。

这是 XML

<register-account success="false">
  <user-name>xxxxx</user-name>
  <password>fghgh</password>
  <email>test@example.com</email>
</register-account>

我试图反序列化的类:

[Serializable, XmlRoot(ElementName = "register-account", Namespace = "MyNamespace")]
[XmlType("register-account")]
public class RegisterAccountResponse
{
    [XmlAttribute("success")]
    public bool Success { get; set; } 

    /// <summary>
    /// Gets or sets the Tennant email address
    /// </summary>
    [XmlElement("email")]
    public string Email { get; set; }

    /// <summary>
    /// Gets or sets the tennant password
    /// </summary>
    [XmlElement("password")]
    public string Password { get; set; }

    /// <summary>
    /// Gets or sets the Tennant username
    /// </summary>
    [XmlElement("user-name")]
    public string Username { get; set; }
}

反序列化方法

public static T Deserialize<T>(string data) where T : class
{

    var ser = new XmlSerializer(typeof(T));

    using (var sr = new StringReader(data))
    {
        return (T)ser.Deserialize(sr);
    }
}

反序列化方法调用

var data = Helper.Deserialize<RegisterAccountResponse>(xml);

例外:

XML 文档 (1, 2) 中存在错误。 ---> System.InvalidOperationException:不是预期的。在 Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderData.Read5_data()

内部异常如下:

<register-account xmlns=''> was not expected.

问题的答案是从类中移除命名空间(移除 Namespace = "MyNamespace")。然而,该类是使用 xsd.exe 自动生成的一个非常大的库的一部分。我不想更改生成的类中的任何内容。是否仍然可以在无需修改课程的情况下解决此问题?

【问题讨论】:

  • 假设这是整个 XML,那么您显示的 XML 没有命名空间(没有 xmlns 声明)。因此,从你的类的序列化参数中删除它是有意义的......或者,通过 XSD 重新生成你的类,使其在没有命名空间的情况下生成。
  • 我认为 XSD.exe 不支持生成没有命名空间属性的类。

标签: .net xml xml-serialization


【解决方案1】:

还有没有办法在不修改类的情况下解决这个问题?

是的。

.NET 有一个名为 XmlAttributeOverrides 的类,专为此目的而设计。 您可以在运行时覆盖代码中存在的属性。

以下修改后的反序列化实用程序方法将使用您提供的 XML 正确反序列化您提供的类的实例,而无需修改任何一个。也没有 XSLT。

    public static T DeserializeWithNoRootNamespace<T>(string data)
        where T : class
    {

        /* Each overridden field, property, or type requires
           an XmlAttributes object. We are overriding the serialization
           of the XmlRoot on the type, so we need one XmlAttributes collection. */
        var attrs = new XmlAttributes();

        /* Create an XmlRootAttribute to override the XmlRoot in-line attr.
           The override will use no namespace. */
        var root = new XmlRootAttribute("register-account");

        // set the XmlRoot on the XmlAttributes collection.
        attrs.XmlRoot= root;

        // Create the XmlAttributeOverrides object.
        var o = new XmlAttributeOverrides();

        /* Map the attributes collection to the thing being 
           overriden (the class). */
        o.Add(typeof(T), attrs);

        // create the serializer, specifying the overrides to use
        var ser = new XmlSerializer(typeof(T), o);

        using (var sr = new StringReader(data))
        {
            return (T)ser.Deserialize(sr);
        }
    }

上面的代码覆盖了 XmlRoot 属性。 XmlAttributeOverrides 足够通用,可以覆盖要反序列化的任何类的 xml 序列化属性。在您的情况下,这不是必需的。

More information.

ps: 不需要您装饰班级的[Serializable] 属性。将其应用于将要进行 XML 序列化和反序列化的类是一个常见错误。但它是无关紧要的,因此是错误的。

【讨论】:

  • 这个很有趣,通过这段代码,我设法覆盖了我的 xml 上的命名空间,也就是说,我的架构有一个命名空间,但由于某种原因,我必须阅读的 xml 文件有不同从供应商到供应商的名称空间。但是有了这个,我可以从文件中读取命名空间,然后在我的反序列化中覆盖它,从而从文件中逐个元素地反序列化。但是..很多运行时代码生成正在进行:'test.vshost.exe'(CLR v4.0.30319:test.vshost.exe):加载'Microsoft.GeneratedCode'。而且速度很慢......还有其他方法可以做到这一点吗?
【解决方案2】:

如果您不能或不想更改代码,那么您必须 xslt 转换您的 xml 以在需要的地方添加一些命名空间。这将有助于反序列化器反序列化文档。

问候。

【讨论】:

  • 我不能更改反序列化代码吗?或更改传入的 xml 以注入命名空间?我该怎么做呢
  • 我不认为你可以避免在你的类中写为属性的命名空间声明。但是您可以使用 XSLT 更改传入的 xml。它可能需要对 XSLT 进行一些研究,因为它是一种标记语言来设置 xml 样式。support.microsoft.com/kb/307322/en-usstackoverflow.com/questions/144713/…
  • 这个答案不正确。不需要 xslt 是不正确的。 @Amine - 你可以做你想做的事。看我的回答。 stackoverflow.com/a/10020010/48082
  • 感谢@Cheeso 的澄清,我错过了我们可以覆盖事物的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
相关资源
最近更新 更多