【问题标题】:C# XML deserialization - missing value - Why?C# XML 反序列化 - 缺失值 - 为什么?
【发布时间】:2014-11-10 01:15:30
【问题描述】:

我有这个 XML

<?xml version="1.0" encoding="utf-8"?>
<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" office:version="1.2" grddl:transformation="http://docs.oasis-open.org/office/1.2/xslt/odf2rdf.xsl">
    <office:meta>
        <meta:creation-date>2014-09-16T11:15:44.96</meta:creation-date>
        <meta:editing-duration>PT00H01M36S</meta:editing-duration>
        <meta:editing-cycles>2</meta:editing-cycles>
        <dc:date>2014-09-16T11:17:09.59</dc:date>
        <meta:document-statistic meta:object-count="24" />
        <meta:generator>OpenOffice.org/3.2$Win32 OpenOffice.org_project/320m12$Build-9483</meta:generator>
    </office:meta>
</office:document-meta>

现在我想反序列化 XML。

我得到了创建日期、日期和生成器等元信息,但对象计数为 NULL 而不是 24,并且 doc.version 也是 NULL,而它应该是 1.2。
我究竟做错了什么 ?

OpenOffice.ODP.Meta.DocumentMeta mydoc = Tools.XML.Serialization.DeserializeXmlFromFile<OpenOffice.ODP.Meta.DocumentMeta>(@"D:\UserName\Tests\Presentation_1.odp\meta.xml");

string ver = mydoc.Version;    
Console.WriteLine(mydoc);
Console.WriteLine(ver);

序列化类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;


namespace Tools.XML
{


    // http://www.switchonthecode.com/tutorials/csharp-tutorial-xml-serialization
    // http://www.codeproject.com/KB/XML/xml_serializationasp.aspx
    public class Serialization
    {


        public static void SerializeToXml<T>(T ThisTypeInstance, string strFileNameAndPath)
        {
            SerializeToXml<T>(ThisTypeInstance, new System.IO.StreamWriter(strFileNameAndPath));
        } // End Sub SerializeToXml


        public static string SerializeToXml<T>(T ThisTypeInstance)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            string strReturnValue = null;

            SerializeToXml<T>(ThisTypeInstance, new System.IO.StringWriter(sb));

            strReturnValue = sb.ToString();
            sb = null;

            return strReturnValue;
        } // End Function SerializeToXml


        public static void SerializeToXml<T>(T ThisTypeInstance, System.IO.TextWriter tw)
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));

            using (System.IO.TextWriter twTextWriter = tw) 
            {
                serializer.Serialize(twTextWriter, ThisTypeInstance);
                twTextWriter.Close();
            } // End Using twTextWriter

            serializer = null;
        } // End Sub SerializeToXml


        public static T DeserializeXmlFromFile<T>(string strFileNameAndPath)
        {
            T tReturnValue = default(T);

            using (System.IO.FileStream fstrm = new System.IO.FileStream(strFileNameAndPath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) 
            {
                tReturnValue = DeserializeXmlFromStream<T>(fstrm);
                fstrm.Close();
            } // End Using fstrm

            return tReturnValue;
        } // End Function DeserializeXmlFromFile


        public static T DeserializeXmlFromEmbeddedRessource<T>(string strRessourceName)
        {
            T tReturnValue = default(T);

            System.Reflection.Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();


            using (System.IO.Stream fstrm = ass.GetManifestResourceStream(strRessourceName)) 
            {
                tReturnValue = DeserializeXmlFromStream<T>(fstrm);
                fstrm.Close();
            } // End Using fstrm

            return tReturnValue;
        } // End Function DeserializeXmlFromEmbeddedRessource


        public static T DeserializeXmlFromStream<T>(System.IO.Stream strm)
        {
            System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
            T ThisType = default(T);

            using (System.IO.StreamReader srEncodingReader = new System.IO.StreamReader(strm, System.Text.Encoding.UTF8)) 
            {
                ThisType = (T)deserializer.Deserialize(srEncodingReader);
                srEncodingReader.Close();
            } // End Using srEncodingReader

            deserializer = null;

            return ThisType;
        } // End Function DeserializeXmlFromStream


        #if notneeded

        public static void SerializeToXML<T>(System.Collections.Generic.List<T> ThisTypeInstance, string strConfigFileNameAndPath)
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(System.Collections.Generic.List<T>));

            using (System.IO.TextWriter textWriter = new System.IO.StreamWriter(strConfigFileNameAndPath)) {
                serializer.Serialize(textWriter, ThisTypeInstance);
                textWriter.Close();
            }

            serializer = null;
        }
        // SerializeToXML


        public static System.Collections.Generic.List<T> DeserializeXmlFromFileAsList<T>(string strFileNameAndPath)
        {
            System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(System.Collections.Generic.List<T>));
            System.Collections.Generic.List<T> ThisTypeList = null;

            using (System.IO.StreamReader srEncodingReader = new System.IO.StreamReader(strFileNameAndPath, System.Text.Encoding.UTF8)) {
                ThisTypeList = (System.Collections.Generic.List<T>)deserializer.Deserialize(srEncodingReader);
                srEncodingReader.Close();
            }

            deserializer = null;

            return ThisTypeList;
        }
        // DeserializeXmlFromFileAsList

        #endif

    } // End Class Serialization


} // End Namespace COR.Tools.XML

XML 持有者:

using System;
using System.Xml.Serialization;
using System.Collections.Generic;


namespace OpenOffice.ODP.Meta
{


    [XmlRoot(ElementName = "document-statistic", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0")]
    public class cDocumentStatistic
    {
        [XmlAttribute(AttributeName = "object-count", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0")]
        public string ObjectCount { get; set; }
    }


    [XmlRoot(ElementName = "meta", Namespace = "urn:oasis:names:tc:opendocument:xmlns:office:1.0")]
    public class Meta
    {
        [XmlElement(ElementName = "creation-date", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0")]
        public string CreationDate { get; set; }

        [XmlElement(ElementName = "editing-duration", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0")]
        public string EditingDuration { get; set; }

        [XmlElement(ElementName = "editing-cycles", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0")]
        public string EditingCycles { get; set; }

        [XmlElement(ElementName = "date", Namespace = "http://purl.org/dc/elements/1.1/")]
        public string Date { get; set; }

        [XmlElement(ElementName = "document-statistic", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0")]
        public cDocumentStatistic DocumentStatistic { get; set; }

        [XmlElement(ElementName = "generator", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0")]
        public string Generator { get; set; }
    }


    [XmlRoot(ElementName = "document-meta", Namespace = "urn:oasis:names:tc:opendocument:xmlns:office:1.0")]
    public class DocumentMeta
    {
        [XmlElement(ElementName = "meta", Namespace = "urn:oasis:names:tc:opendocument:xmlns:office:1.0")]
        public Meta Meta { get; set; }

        [XmlAttribute(AttributeName = "meta", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string _Meta { get; set; }

        [XmlAttribute(AttributeName = "office", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Office { get; set; }

        [XmlAttribute(AttributeName = "xlink", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Xlink { get; set; }

        [XmlAttribute(AttributeName = "dc", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Dc { get; set; }

        [XmlAttribute(AttributeName = "presentation", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Presentation { get; set; }

        [XmlAttribute(AttributeName = "ooo", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Ooo { get; set; }

        [XmlAttribute(AttributeName = "smil", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Smil { get; set; }

        [XmlAttribute(AttributeName = "anim", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Anim { get; set; }

        [XmlAttribute(AttributeName = "grddl", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Grddl { get; set; }

        [XmlAttribute(AttributeName = "officeooo", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Officeooo { get; set; }

        [XmlAttribute(AttributeName = "version", Namespace = "urn:oasis:names:tc:opendocument:xmlns:office:1.0")]
        public string Version { get; set; }

        [XmlAttribute(AttributeName = "transformation", Namespace = "http://www.w3.org/2003/g/data-view#")]
        public string Transformation { get; set; }
    }


}

补充问题:
有人知道持续时间格式是什么吗?

【问题讨论】:

    标签: c# xml xml-serialization xmlserializer openoffice-impress


    【解决方案1】:

    这是因为反序列化器有问题。
    因为标准规定如果元素命名空间相同,您可以省略属性命名空间。另一方面,这显然并不意味着您绝对必须省略属性命名空间,因为元素命名空间相同。

    参见XML Specthis

    解决方案是以某种方式设置一个与包含命名空间不同的根命名空间,但不影响实际的根命名空间...

    如果有一个 XmlElement,这是可能的,因为如果你在一个单独的类中有它,你可以在那里设置 XmlRoot,并在实际引用它的类中设置另一个命名空间。

    在代码中,这很简单:

    [XmlRoot(ElementName = "document-statistic", Namespace = "")]
    public class cDocumentStatistic
    {
        [XmlAttribute(AttributeName = "object-count", Namespace = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0" )]
        public string ObjectCount { get; set; }
    }
    

    版本的解决方案有点复杂:因为它是一个属性,你不能在序列化器中设置 xmlroot (不管它是什么,那是实际的错误)...

    所以你必须拼凑一个 XmlTextReader,它忽略版本上的命名空间,但不忽略其余部分......就像这样

        // https://stackoverflow.com/questions/870293/can-i-make-xmlserializer-ignore-the-namespace-on-deserialization
        // helper class to ignore namespaces when de-serializing
        public class NamespaceIgnorantXmlTextReader : System.Xml.XmlTextReader
        {
            public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader) : base(reader) { }
    
            public override string NamespaceURI
            {
    
                get
                { //return ""
                    // string nam = base.Name;
                    // Console.WriteLine(this.Name);
                    // Console.WriteLine(this.LocalName);
    
                    if (StringComparer.InvariantCultureIgnoreCase.Equals(this.Name, "office:version"))
                    {
                        return "";
                    }
    
    
    
                    // Console.WriteLine(nam);
                    return base.NamespaceURI;
                }
            }
        }
    

    然后你仍然需要告诉序列化器实际使用这个abdomination

    public static T DeserializeXmlFromStream<T>(System.IO.Stream strm)
    {
        System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
        T ThisType = default(T);
    
    
    
        using (System.IO.StreamReader srEncodingReader = new System.IO.StreamReader(strm, System.Text.Encoding.UTF8)) 
        {
            // ThisType = (T)deserializer.Deserialize(srEncodingReader);
    
            using (NamespaceIgnorantXmlTextReader SpecialNamespaceReaderBecauseMicrosoftSucks = new NamespaceIgnorantXmlTextReader(srEncodingReader))
            {
                ThisType = (T)deserializer.Deserialize(SpecialNamespaceReaderBecauseMicrosoftSucks);
                SpecialNamespaceReaderBecauseMicrosoftSucks.Close();
            } // End Using SpecialNamespaceReaderBecauseMicrosoftSucks
    
            srEncodingReader.Close();
        } // End Using srEncodingReader
    
        deserializer = null;
    
        return ThisType;
    } // End Function DeserializeXmlFromStream
    

    【讨论】:

      【解决方案2】:

      我运行了您的代码,发现您需要对文件进行一些更改。

      请注意,您不需要为 object_count 和 version 指定命名空间,因为它们的标签都在开头指定了它们的命名空间 对于 version office 在标签本身中指定 office:document-meta

      object_count 命名空间元相同,在标签 meta:document-statistic

      中指定

      这是更新的:

      <?xml version="1.0" encoding="utf-8"?>
      <office:document-meta 
      xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
      xmlns:xlink="http://www.w3.org/1999/xlink" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
      xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 
      xmlns:ooo="http://openoffice.org/2004/office" 
      xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" 
      xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" 
      xmlns:grddl="http://www.w3.org/2003/g/data-view#" 
      xmlns:officeooo="http://openoffice.org/2009/office" 
      version="1.2" 
      grddl:transformation="http://docs.oasis-open.org/office/1.2/xslt/odf2rdf.xsl">
          <office:meta>
              <meta:creation-date>2014-09-16T11:15:44.96</meta:creation-date>
              <meta:editing-duration>PT00H01M36S</meta:editing-duration>
              <meta:editing-cycles>2</meta:editing-cycles>
              <dc:date>2014-09-16T11:17:09.59</dc:date>
              <meta:document-statistic object-count="24" />
              <meta:generator>OpenOffice.org/3.2$Win32 OpenOffice.org_project/320m12$Build-9483</meta:generator>
          </office:meta>
      </office:document-meta>
      

      希望这会有所帮助 :)

      【讨论】:

      • 这行得通,但这不好,我不能修改 OpenOffice,这是 XML 的来源和去向...问题必须通过修改类而不是 XML 以某种方式解决文件。而且我当然不想开始在 XML 文档中使用 Replace。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-14
      • 2012-10-28
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 2011-02-23
      • 2012-09-08
      相关资源
      最近更新 更多