代码之家  ›  专栏  ›  技术社区  ›  Natalie Perret

为什么由于根元素中的前缀而无法反序列化XML字符串?

  •  1
  • Natalie Perret  · 技术社区  · 6 年前

    我有以下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; }
    }
    

    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). ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.

    读一些像这样的帖子: https://stackoverflow.com/a/36163079/4636721 好像有个虫子 XmlSerializer .

    1 回复  |  直到 6 年前
        1
  •  2
  •   dbc    6 年前

    异常的原因是 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) 使文本读取器前进一点,因此如果稍后尝试从 字符串读取器

    数据模型中也有一些错误。它应该看起来像:

    [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 因此不应映射到数据模型中的成员。

    • 的子元素 <y:instance ...> XmlSerializer 假设它们应该与包含元素在同一个命名空间中,这里 http://www.blahblah.com/engine/42" .

      因此有必要补充 [XmlType(Namespace = "")] Instance 为从中创建的所有子元素指示正确的命名空间 . (另一个选择是 [XmlElement(Form = XmlSchemaForm.Unqualified)]

    • 对…的定义 Language 不包括在你的问题里,所以我包括了一个。

    • StreamReader 而不是先读到 string ,然后从 使用 StringReader .

    工作样品小提琴 here