【问题标题】:Why an XML string cannot be deserialized due to prefixes in root elements?为什么由于根元素中的前缀而无法反序列化 XML 字符串?
【发布时间】:2018-08-13 01:12:30
【问题描述】:

我有下面的 XML:

<y:input xmlns:y='http://www.blahblah.com/engine/42'>
    <y:datas>
        <y:instance yclass='ReportPeriod' yid="report">
            <language yid='en'/>
            <threshold>0.6</threshold>
            <typePeriod>predefinedPeriod</typePeriod>
            <interval>month</interval>
            <valuePeriod>April</valuePeriod>
            <fund yclass="Fund">
                <name>K</name>
                <indexName>CAC40</indexName>
            </fund>
        </y:instance>
    </y:datas>
</y:input>

我正在尝试反序列化为

[XmlRoot(ElementName="fund")]
public class Fund 
{
    [XmlElement(ElementName="name")]
    public string Name { get; set; }

    [XmlElement(ElementName="indexName")]
    public string IndexName { get; set; }

    [XmlAttribute(AttributeName="yclass")]
    public string Yclass { get; set; }
}

[XmlRoot(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public class Instance 
{
    [XmlElement(ElementName="language")]
    public Language Language { get; set; }

    [XmlElement(ElementName="threshold")]
    public string Threshold { get; set; }

    [XmlElement(ElementName="typePeriod")]
    public string TypePeriod { get; set; }

    [XmlElement(ElementName="interval")]
    public string Interval { get; set; }

    [XmlElement(ElementName="valuePeriod")]
    public string ValuePeriod { get; set; }

    [XmlElement(ElementName="fund")]
    public Fund Fund { get; set; }

    [XmlAttribute(AttributeName="yclass")]
    public string Yclass { get; set; }

    [XmlAttribute(AttributeName="yid")]
    public string Yid { get; set; }
}

[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
    [XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
    public Instance Instance { get; set; }
}

[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
    [XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
    public Datas Datas { get; set; }

    [XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
    public string Y { get; set; }
}

但是,在反序列化上述 XML 时:

public static class Program
{
    public static void Main(params string[] args)
    {
        var serializer = new XmlSerializer(typeof(Input));
        using (var stringReader = new StringReader(File.ReadAllText("file.xml")))
        {
            using(var xmlReader = XmlReader.Create(stringReader))
            {
                var instance = (Input)serializer.Deserialize(stringReader);
            }
        }
    }
}

由于y 前缀,我收到一个错误...

There is an error in XML document (1, 1). ---&gt; System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.

阅读一些类似的帖子:https://stackoverflow.com/a/36163079/4636721 似乎XmlSerializer 可能存在错误。

【问题讨论】:

  • 标识行在哪里:

标签: c# .net xml xmlserializer xml-deserialization


【解决方案1】:

异常的原因是您将stringReader 而不是xmlReader 传递给serializer.Deserialize()。您应该改为传递 XML 阅读器:

Input instance = null;
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StreamReader("file.xml"))
{
    using(var xmlReader = XmlReader.Create(stringReader))
    {
        instance = (Input)serializer.Deserialize(xmlReader);
    }
}   

(显然XmlReader.Create(stringReader) 使文本阅读器前进了一点,因此如果您稍后尝试直接从stringReader 读取,它已移过根元素。)

您的数据模型中也存在一些错误。它应该看起来像:

[XmlRoot(ElementName="fund")]
public class Fund 
{
    [XmlElement(ElementName="name")]
    public string Name { get; set; }

    [XmlElement(ElementName="indexName")]
    public string IndexName { get; set; }

    [XmlAttribute(AttributeName="yclass")]
    public string Yclass { get; set; }
}

[XmlRoot(ElementName="instance")]
[XmlType(Namespace = "")] // Add this
public class Instance 
{
    [XmlElement(ElementName="language")]
    public Language Language { get; set; }

    [XmlElement(ElementName="threshold")]
    public string Threshold { get; set; }

    [XmlElement(ElementName="typePeriod")]
    public string TypePeriod { get; set; }

    [XmlElement(ElementName="interval")]
    public string Interval { get; set; }

    [XmlElement(ElementName="valuePeriod")]
    public string ValuePeriod { get; set; }

    [XmlElement(ElementName="fund")]
    public Fund Fund { get; set; }

    [XmlAttribute(AttributeName="yclass")]
    public string Yclass { get; set; }

    [XmlAttribute(AttributeName="yid")]
    public string Yid { get; set; }
}

[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
    [XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
    public Instance Instance { get; set; }
}

[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
    [XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
    public Datas Datas { get; set; }

    //Remove This
    //[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
    //public string Y { get; set; }
}

// Add this
[XmlRoot(ElementName="language")]
public class Language 
{
    [XmlAttribute(AttributeName="yid")]
    public string Yid { get; set; }
}

注意事项:

  • xmlns:y='http://www.blahblah.com/engine/42'XML namespace declaration,因此不应映射到数据模型中的成员。

  • &lt;y:instance ...&gt; 的子元素不在任何命名空间中。除非子元素的命名空间以某种方式由属性指定,否则XmlSerializer 将假定它们应该与包含元素位于同一命名空间中,此处为http://www.blahblah.com/engine/42"

    因此有必要将[XmlType(Namespace = "")] 添加到Instance 以指示从Instance 创建的所有子元素的正确命名空间。 (另一种选择是将[XmlElement(Form = XmlSchemaForm.Unqualified)] 添加到每个成员,但我认为在类型上设置单个属性更容易。)

  • Language 的定义未包含在您的问题中,因此我包含了一个。

  • 使用StreamReader 直接从文件反序列化比先读入string,然后使用StringReaderstring 反序列化更有效。

工作样本小提琴here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    相关资源
    最近更新 更多