C # Десериализация XML - отсутствующее значение - Почему?

У меня есть этот 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; }
    }


}

Дополнительный вопрос:
Кто-нибудь знает, что такое формат продолжительности?


person Stefan Steiger    schedule 16.09.2014    source источник


Ответы (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>

Надеюсь это поможет :)

person Akanksha Gaur    schedule 16.09.2014
comment
Это работает, но это нехорошо, я не могу изменять OpenOffice, откуда исходит XML и куда идет ... Проблема должна быть каким-то образом решена путем изменения класса, а не файла XML. И я, конечно, не хочу начинать копаться в Replace в XML-документе. - person Stefan Steiger; 16.09.2014

Это потому, что десериализатор неисправен.
Поскольку стандарт говорит, что вы можете опустить пространство имен атрибутов, если пространство имен элементов такое же. С другой стороны, это, очевидно, не означает, что вам абсолютно необходимо исключить пространство имен атрибутов только потому, что пространство имен элементов такое же.

См. спецификацию XML и это.

Решение состоит в том, чтобы каким-то образом установить корневое пространство имен, которое не совпадает с содержащим пространство имен, но оставить фактическое корневое пространство имен незатронутым ...

Если у кого-то есть 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;
            }
        }
    }

И тогда вам все равно нужно указать сериализатору, чтобы он действительно использовал эту абдоминацию.

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
person Stefan Steiger    schedule 16.09.2014