为什么我需要移除xmlns属性才能反序列化我的XML文件?

4

问题

我正在使用Xsd2Code(一款用于XSD模式的.NET类生成器)来处理一个简单的设置文件模式。但是,当我尝试使用内置的LoadFromFile()Deserialize()方法时,我会收到一个异常,这个异常似乎与我的XSD和XML文件中的xmlns属性有关。如果我删除这些属性,异常就会消失。(请参见下面的“更新”以获取实际引发异常的代码详细信息。)


XSD 文件

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
  xmlns="Myco.CLDatabaseBuilder.Models"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="Myco.CLDatabaseBuilder.Models"
  elementFormDefault="qualified">
  <xs:element name="Settings" type="Settings" />
  <xs:complexType name="Settings">
    <xs:sequence>
      <xs:element name="SqlServerInstanceName" type="xs:string" />
      <xs:element name="DatabaseName" type="xs:string" />
      <xs:element name="RootDatabaseName" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

XML文件(失败) - 当我尝试反序列化时,会出现异常。

<?xml version="1.0" encoding="UTF-8"?>
<Settings
  xmlns="Myco.CLDatabaseBuilder.Models"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="Myco.CLDatabaseBuilder.Models Settings.xsd">
  <SqlServerInstanceName>SQLEXPRESS</SqlServerInstanceName>
  <DatabaseName>CL</DatabaseName>
  <RootDatabaseName>master</RootDatabaseName>
</Settings>

XML文件(成功) - 反序列化正常工作

<?xml version="1.0" encoding="UTF-8"?>
<Settings
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="Myco.CLDatabaseBuilder.Models Settings.xsd">
  <SqlServerInstanceName>SQLEXPRESS</SqlServerInstanceName>
  <DatabaseName>CL</DatabaseName>
  <RootDatabaseName>master</RootDatabaseName>
</Settings>

异常详情 - 如果我运行“失败示例”,会发生什么

A first chance exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
System.InvalidOperationException: There is an error in XML document (2, 2). ---> System.InvalidOperationException: <Settings xmlns='Myco.CLDatabaseBuilder.Models'> was not expected.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderSettings.Read3_Settings()
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader)
   at Myco.CLDatabaseBuilder.Models.Settings.Deserialize(String xml) in C:\...\CLDatabaseBuilder\Models\Settings.cs:line 118
   at Myco.CLDatabaseBuilder.Models.Settings.LoadFromFile(String fileName) in C:\...\CLDatabaseBuilder\Models\Settings.cs:line 195
   at Myco.CLDatabaseBuilder.Program.InitializeSettings() in C:\...\CLDatabaseBuilder\Program.cs:line 68

问题:

基本上,我必须剥离默认命名空间才能进行反序列化。

请问当我使用xmlns时为什么会出现异常? 在Visual Studio中执行实时验证非常有用,因此如果可能的话,我希望保留它。

我的XSD根元素属性是否存在问题? 我已经更改了elementFormDefault(从qualified更改为unqualified),但这并没有解决问题。


更新

实际上代码卡在这里:

Serializer = new System.Xml.Serialization.XmlSerializer(typeof(Myco.CDDatabaseBuilder.Models.Settings));
Serializer.Deserialize(System.Xml.XmlReader.Create(stringReader));

如上所示的异常,我遇到的错误是:

<Settings xmlns='Myco.CLDatabaseBuilder.Models'> was not expected.

这是否暗示了在我的 Settings 类(由 Xsd2Code 生成的类)中需要查找的内容?这个类中散布着 [System.Xml.Serialization...] 属性。我想知道是否有什么丢失了,或者该类(或序列化器)没有一种建模默认 xmlns 属性的方法。任何想法都欢迎。
2个回答

8

有些日子...结果我需要四个小字符。

Xsd2Code中有一个开关/xa+,它设置了GenerateXMLAttributes = true

由于某种原因,默认情况下为false。如果您有一个xmlns属性并且想进行反序列化,则需要将其设置为true。


3

我不知道问题出在哪里,但它应该可以工作。你的困惑是正确的。我用.NET SDK附带的xsd.exe工具运行了你的模式。它从你的模式生成这个类:

[XmlType(Namespace="Myco.CLDatabaseBuilder.Models")]
[XmlRoot(Namespace="Myco.CLDatabaseBuilder.Models", IsNullable=false)]
public partial class Settings {

    private string sqlServerInstanceNameField;

    private string databaseNameField;

    private string rootDatabaseNameField;

    /// <remarks/>
    public string SqlServerInstanceName {
        get {
            return this.sqlServerInstanceNameField;
        }
        set {
            this.sqlServerInstanceNameField = value;
        }
    }

    /// <remarks/>
    public string DatabaseName {
        get {
            return this.databaseNameField;
        }
        set {
            this.databaseNameField = value;
        }
    }

    /// <remarks/>
    public string RootDatabaseName {
        get {
            return this.rootDatabaseNameField;
        }
        set {
            this.rootDatabaseNameField = value;
        }
    }
}

正如您所看到的,这个类中只有一些属性进行了装饰。有一个XmlType和一个XmlRoot,就是这样。即使没有XmlElement属性,该类中的三个属性也会被隐式序列化。

我从重新序列化你的XML中得到的结果是:

<q1:Settings xmlns:q1="Myco.CLDatabaseBuilder.Models">
  <q1:SqlServerInstanceName>SQLEXPRESS</q1:SqlServerInstanceName>
  <q1:DatabaseName>CL</q1:DatabaseName>
  <q1:RootDatabaseName>master</q1:RootDatabaseName>
</q1:Settings>

+1 鼓励一下,但我已经找到了问题的解决方法(请看我的回答)。有趣的是,当你重新序列化时,它会使用 xmlns:q1 而不是使用默认命名空间。 - devuxer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接