I have this 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>
Now I want to deserialize the XML.
I get the meta information like creation-date, date, and generator, but object-count is NULL instead of 24, and doc.version is also NULL, while it should be 1.2.
What am I doing wrong ?
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);
Serialization class:
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 holder:
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; }
}
}
Additional question:
Does anybody know what the duration format is ?
This is because the deserializer is buggy.
Because the standard says you can omit the attribute namespace if the element namespace is the same. On the other hand, that obviously doesn't mean you absolutely have to omit the attribute namespace just because the element namespace is the same.
The solution is to somehow set a root-namespace that is not the same as the containing namespace, but leave the actual root-namespace unaffected...
If one has a XmlElement, that's possible because you can set XmlRoot there if you have it in a separate class, and set another namespace in the class where it is actually referenced.
In code, that's simply:
[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; }
}
The solution for version is a bit more complex: since it's an attribute, you cannot set xmlroot in the serializer (whyever that is as it is, that is the actual bug)...
So you have to hack together a XmlTextReader that ignores the namespaces on version, but doesn't ignore them on the rest... That goes like this
// 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;
}
}
}
And then you still have to tell the serializer to actually use this 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