I'm trying to figure out how to use XmlTextReader and XmlTextWriter for the configuration file of my program(s).
The xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Base>
<Global>
<some_config_value>86400</some_config_value>
<test1>t_1</test1>
<test2>t_2</test2>
<test3>t_3</test3>
<test4>t_4</test4>
</Global>
<test_head>
<test5>t_5</test5>
<test6>t_6</test6>
</test_head>
</Base>
And here is the class I have so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace my_program.Global
{
class CXMLConfig
{
private string path;
public CXMLConfig(string filepath)
{
path = filepath;
}
public string XmlReadValue(string Section, string Key)
{
XmlTextReader textReader = new XmlTextReader(path);
ReadElements readEl = new ReadElements(textReader, Section, Key);
textReader.Close();
return readEl.Value;
}
private class ReadElements
{
XmlTextReader textReader;
string Section;
string Key;
private bool inBase = false;
private bool inSection = false;
private bool inKey = false;
public string Value { get; private set; }
public ReadElements(XmlTextReader textReader_set, string Section_set, string Key_set)
{
Value = "";
this.textReader = textReader_set;
this.Section = Section_set;
this.Key = Key_set;
textReader.Read();
while (textReader.Read())
{
// Move to fist element
textReader.MoveToElement();
string nodetype = textReader.NodeType.ToString();
if (textReader.LocalName == "Base")
{
if (nodetype == "Element")
{
if (!inBase)
inBase = true;
}
else if (nodetype == "EndElement")
{
if (inBase)
inBase = false;
}
}
else if (inBase && textReader.LocalName == Section)
{
if (nodetype == "Element")
{
if (!inSection)
inSection = true;
}
else if (nodetype == "EndElement")
{
if (inSection)
inSection = false;
}
}
else if (inBase && inSection && textReader.LocalName == Key)
{
if (inSection)
{
if (nodetype == "Element")
{
if (!inKey)
inKey = true;
}
else if (nodetype == "EndElement")
{
if (inKey)
inKey = false;
}
}
}
else if (inBase && inSection && inKey)
{
if (nodetype == "Text")
{
Value = textReader.Value.ToString();
//Console.WriteLine(Value);
}
}
}
}
}
}
}
So first of all, this is probably bad XML.. I have never used it before and it does look a little.. odd. And then there is the fact that I wrote this whole ReadElements class to read a value out of the config file, but I imagined there would be a much simpler way to do this with XmlTextReader (but I couldn't find it). And then lastly, I have yet to figure out how to update a value in the xml file using XmlTextWriter without re-writing the whole xml file from top to bottom.
You could use XmlSerializer to serialize and deserialize an arbitrary configuration class. Here is a sample implementation:
public enum MyEnum
{
ValueA,
ValueB
}
[Serializable]
public class Configuration : PersistableObject
{
public double A { get; set; }
public string B { get; set; }
public MyEnum C { get; set; }
}
public class PersistableObject
{
public static T Load<T>(string fileName) where T : PersistableObject, new()
{
T result = default(T);
using (FileStream stream = File.OpenRead(fileName))
{
result = new XmlSerializer(typeof(T)).Deserialize(stream) as T;
}
return result;
}
public void Save<T>(string fileName) where T : PersistableObject
{
using (FileStream stream = new FileStream(fileName, FileMode.CreateNew))
{
new XmlSerializer(typeof(T)).Serialize(stream, this);
}
}
}
For more information on how to configure XmlSerializer, have a look at the MSDN article: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
Related
i am building a dictionary WPF application where you write a word and than the application tells u in what language the word is and also gives you a description of the word. Using MVVM.
Here is how it looks:
I have problem with finding out how to get the language and the description of word from a text file and put them in the text box, i dont mean the binding, but the exact method of getting the info.
Here is my Model:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
namespace dictionary
{
public class dictionaryModel
{
private string word;
private string language;
private string description;
public string Word
{
get
{
return word;
}
set
{
word = value;
}
}
public string Language
{
get
{
return language;
}
set
{
language = value;
}
}
public string Description
{
get
{
return description;
}
set
{
description = value;
}
}
public dictionaryModel(string describedWord, string WordLanguage, string WordDescription)
{
this.word = describedWord;
this.language = WordLanguage;
this.description = WordDescription;
}
public dictionaryModel()
{ }
}
and here is my View Model, so far:
namespace dictionary
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
public class dictionaryViewModel : INotifyPropertyChanged
{
private ICommand _getAnswer;
private dictionaryModel m;
private string w;
private string retLanguage;
private string retDescription;
private bool _canExecute;
public dictionaryViewModel()
{
_canExecute = true;
}
public string retLang
{
get
{
return retLanguage;
}
set
{
retLanguage = value;
NotifyPropertyChanged();
}
}
public string retDescr
{
get
{
return retDescription;
}
set
{
retDescription = value;
NotifyPropertyChanged();
}
}
public string word
{
get
{
return w;
}
set
{
w = value;
NotifyPropertyChanged();
}
}
public dictionaryModel model
{
get
{
return m;
}
set
{
m = value;
NotifyPropertyChanged();
}
}
public ICommand getAnswer
{
get
{
return _getAnswer ?? (_getAnswer = new RelayCommand(() => getWholeAnswer(word), _canExecute));
}
}
public dictionaryViewModel(dictionaryModel model, string word, string retLang, string retDescr,
ICommand getAnswer)
{
m = model;
w = word;
retLang = retLanguage;
retDescr = retDescription;
_getAnswer = getAnswer;
}
public ObservableCollection<dictionaryModel> readTxtFile()
{
ObservableCollection<dictionaryModel> dictObj = new ObservableCollection<dictionaryModel>();
string word;
string language;
string description;
var file = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "dictionary.txt");
StreamReader read = new StreamReader(file);
string line;
string[] item;
while((line=read.ReadLine())!=null)
{
item = line.Split(';');
word = item[0];
language = item[1];
description = item[2];
dictionaryModel object1 = new dictionaryModel(word, language, description);
dictObj.Add(object1);
}
read.Close();
return dictObj;
}
public void getWholeAnswer(string w)
{
string descr, lang;
dictionaryModel obj = null;
ObservableCollection<dictionaryModel> rdF = readTxtFile();
try
{
foreach(dictionaryModel a in rdF)
{
if(w.Equals(a))
{
descr = retDescr;
lang = retLang;
obj = a;
}
obj.Language = retLang;
obj.Description = retDescription;
}
}catch(Exception e)
{
ExceptionInfo();
}
}
private void ExceptionInfo()
{
throw new NotImplementedException();
}
private void NotifyPropertyChanged()
{
throw new NotImplementedException();
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
The method is getWholeAnswer(). You see what i have tried, but no success. If you have any ideas, please help me out...
I think the problem is here:
if(w.Equals(a))
w is a string, while a is dictionaryModel, you are comparing two different kind of types without defining an equality logic.
Maybe you would replace that line with this?
if(string.Compare(w.Trim(), a.word, true) == 0)
string.Compare reference on MSDN
string.Trim reference on MSDN
i found my mistake, i am posting the solution of the method, it could be helpful to someone:
public void getWholeAnswer(string w)
{
dictionaryModel obj = null;
ObservableCollection<dictionaryModel> rdF = readTxtFile();
bool find = false;
try
{
foreach(dictionaryModel a in rdF)
{
if(w.Equals(a.Word))
{
obj = a;
retLang = a.Language;
retDescr = a.Description;
find = true;
break;
}
}
if(false == find)
{
AskTheQuestion();
}
}catch(Exception e)
{
AskTheQuestion();
}
}
I have an XML source that I can't change and I want to deserialise this using XmlSerializer.
I can do this fine however there are some arrays of custom classes that I would like to access the array by a String and not in Integer.
I know I can use
public ClassName this[string index]
but I can't work out where to add this to my Class.
I want to be able to call
Object.Transaction["TransactionTypeName"]
instead of
Object.Transaction[0]
This is a stripped down version of the class.
public partial class Configuration
{
private ConfigurationTransaction[] transactionsField;
[System.Xml.Serialization.XmlArrayItemAttribute("Transaction", IsNullable = false)]
public List<ConfigurationTransaction> Transactions
{
get
{
return this.transactionsField;
}
set
{
this.transactionsField = value;
}
}
}
public partial class ConfigurationTransaction
{
private string typeField;
[System.Xml.Serialization.XmlAttributeAttribute()]
public string type
{
get
{
return this.typeField;
}
set
{
this.typeField = value;
}
}
}
A simplified example code of your classes with indexer.
While we need to save the value to access the indexer will have to create additional class.
public class Configuration
{
public ConfigurationTransaction this[string transactionName]
{
get
{
return Transactions.First(tran => tran.TransactionName == transactionName).ConfigurationTransaction;
}
set
{
int index = Transactions.FindIndex(tran => tran.TransactionName == transactionName);
if (index >= 0)
Transactions[index] = new PairHelper { TransactionName = transactionName, ConfigurationTransaction = value };
else
Transactions.Add(new PairHelper { TransactionName = transactionName, ConfigurationTransaction = value });
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public List<PairHelper> Transactions { get; set; }
}
public class ConfigurationTransaction
{
[XmlAttribute()]
public string Type { get; set; }
}
public class PairHelper
{
public string TransactionName { get; set; }
public ConfigurationTransaction ConfigurationTransaction { get; set; }
}
It's work:
Configuration conf = new Configuration();
conf.Transactions = new List<PairHelper>();
conf["fooTran"] = new ConfigurationTransaction { Type = "foo" };
conf["barTran"] = new ConfigurationTransaction { Type = "bar" };
var xs = new XmlSerializer(typeof(Configuration));
using (var fs = new FileStream("test.txt", FileMode.Create))
{
xs.Serialize(fs, conf);
}
Configuration conf2;
using (var fs = new FileStream("test.txt", FileMode.Open))
{
conf2 = (Configuration)xs.Deserialize(fs);
}
foreach (var tran in conf2.Transactions)
Console.WriteLine(tran.TransactionName + " : " + tran.ConfigurationTransaction);
Console.WriteLine(conf2["fooTran"].Type);
Console.WriteLine(conf2["barTran"].Type);
XML will look like this:
<?xml version="1.0"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Transactions>
<PairHelper>
<TransactionName>fooTran</TransactionName>
<ConfigurationTransaction Type="foo" />
</PairHelper>
<PairHelper>
<TransactionName>barTran</TransactionName>
<ConfigurationTransaction Type="bar" />
</PairHelper>
</Transactions>
</Configuration>
I was able to add in this into the Configuration class.
public ConfigurationTransaction this[String index]
{
get
{
foreach (var item in Transactions)
{
if (item.type.ToLower().Trim() == index.ToLower().Trim())
{
return item;
}
}
return null;
}
}
And call it like
Object["TransactionTypeName"]
I think that's what I did anyway, I ended up manually importing all the data into a SQL database and creating an Entity Framework class to access it and depricated the XML solution.
I have
properties that have ids and values and a name. Can I represent all those with a single class using XmlElement/XmlArray C# annotations? I would like to derive the xml element name from the class attribute name;
my class would look like:
public class Property {
public string name; //could be enum
public int id;
public string value;
}
e.g:
new Property("property1name",2,"testvalue");
new Property("property2name",10,"anothervalue");
I would like to have xml that looks like:
<property1name><id>2</id><value>testvalue</value></property1name>
<property2name><id>10</id><value>anothervalue</value></property2name>
instead of the usual
<property><name>property1name</name><id>2</id><value>testvalue</value></property>
<property><name>property2name</name><id>10</id><value>anothervalue</value></property>
In other words the xmlelement gets its name from attribute name of the class Property
Update
And here's a quick adaptation to handle your Property class. First, a List<T> subclass that implements IXmlSerializable:
public interface IHasElementName
{
string ElementName { get; set; }
}
public class XmlNamedElementList<T> : List<T>, IXmlSerializable where T : IHasXmlElementName
{
// https://msdn.microsoft.com/en-us/library/System.Xml.Serialization.XmlSerializer%28v=vs.110%29.aspx
// Any serializer created with the "XmlSerializer(typeof(T), rootAttribute)" must be cached
// to avoid resource & memory leaks.
class ValueSerializerCache
{
// By using a nested class with a static constructor, we defer generation of the XmlSerializer until it's actually required.
static ValueSerializerCache()
{
var rootAttribute = new XmlRootAttribute();
rootAttribute.ElementName = ValueTypeName;
rootAttribute.Namespace = ValueTypeNamespace;
serializer = new XmlSerializer(typeof(T), rootAttribute);
}
static readonly XmlSerializer serializer;
internal static XmlSerializer Serializer { get { return serializer; } }
}
static string ValueTypeName { get { return typeof(T).DefaultXmlElementName(); } }
static string ValueTypeNamespace { get { return typeof(T).DefaultXmlElementNamespace(); } }
#region IXmlSerializable Members
XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
if (reader.IsEmptyElement)
{
reader.Read();
return;
}
var typeName = ValueTypeName;
reader.ReadStartElement(); // Advance to the first sub element of the list element.
while (reader.NodeType == XmlNodeType.Element)
{
var name = reader.Name;
using (var subReader = reader.ReadSubtree())
{
var doc = XDocument.Load(subReader);
if (doc != null && doc.Root != null)
{
doc.Root.Name = doc.Root.Name.Namespace + typeName;
using (var docReader = doc.CreateReader())
{
var obj = ValueSerializerCache.Serializer.Deserialize(docReader);
if (obj != null)
{
T value = (T)obj;
value.ElementName = XmlConvert.DecodeName(name);
Add(value);
}
}
}
}
// Move past the end of item element
reader.Read();
}
// Move past the end of the list element
reader.ReadEndElement();
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
foreach (var value in this)
{
XDocument doc = new XDocument();
using (var subWriter = doc.CreateWriter())
{
// write xml into the writer
ValueSerializerCache.Serializer.Serialize(subWriter, value);
}
if (doc.Root == null)
continue;
doc.Root.Name = doc.Root.Name.Namespace + XmlConvert.EncodeName(value.ElementName);
// Remove redundant namespaces.
foreach (var attr in doc.Root.Attributes().ToList())
{
if (!attr.IsNamespaceDeclaration || string.IsNullOrEmpty(attr.Value))
continue;
var prefix = writer.LookupPrefix(attr.Value);
if ((prefix == attr.Name.LocalName)
|| (prefix == string.Empty && attr.Name == "xmlns"))
attr.Remove();
}
doc.Root.WriteTo(writer);
}
}
#endregion
}
public static class XmlSerializationHelper
{
static Attribute GetCustomAttribute(MemberInfo element, Type attributeType)
{
return Attribute.GetCustomAttribute(element, attributeType);
}
static T GetCustomAttribute<T>(MemberInfo element) where T : Attribute
{
return (T)GetCustomAttribute(element, typeof(T));
}
public static string DefaultXmlElementName(this Type type)
{
var xmlType = GetCustomAttribute<XmlTypeAttribute>(type);
if (xmlType != null && !string.IsNullOrEmpty(xmlType.TypeName))
return xmlType.TypeName;
var xmlRoot = GetCustomAttribute<XmlRootAttribute>(type);
if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.ElementName))
return xmlRoot.ElementName;
return type.Name;
}
public static string DefaultXmlElementNamespace(this Type type)
{
var xmlType = GetCustomAttribute<XmlTypeAttribute>(type);
if (xmlType != null && !string.IsNullOrEmpty(xmlType.Namespace))
return xmlType.Namespace;
var xmlRoot = GetCustomAttribute<XmlRootAttribute>(type);
if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.Namespace))
return xmlRoot.Namespace;
return string.Empty;
}
public static string GetXml<T>(this T obj)
{
return GetXml(obj, false);
}
public static string GetXml<T>(this T obj, bool omitNamespace)
{
return GetXml(obj, new XmlSerializer(obj.GetType()), omitNamespace);
}
public static string GetXml<T>(this T obj, XmlSerializer serializer)
{
return GetXml(obj, serializer, false);
}
public static string GetXml<T>(T obj, XmlSerializer serializer, bool omitStandardNamespaces)
{
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
{
ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
}
return GetXml(obj, serializer, ns);
}
public static string GetXml<T>(T obj, XmlSerializerNamespaces ns)
{
return GetXml(obj, new XmlSerializer(obj.GetType()), ns);
}
public static string GetXml<T>(T obj, XmlSerializer serializer, XmlSerializerNamespaces ns)
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true; // For cosmetic purposes.
settings.IndentChars = " "; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
if (ns != null)
serializer.Serialize(xmlWriter, obj, ns);
else
serializer.Serialize(xmlWriter, obj);
}
return textWriter.ToString();
}
}
}
And use it like:
public class Property : IHasElementName
{
public Property()
{
}
public Property(string name, int id, string value)
{
this.name = name;
this.id = id;
this.value = value;
}
[XmlIgnore]
public string name; //could be enum
public int id;
public string value;
#region IHasElementName Members
[XmlIgnore]
string IHasElementName.ElementName { get { return name; } set { name = value; } }
#endregion
}
public class RootObject
{
public RootObject()
{
this.Properties = new XmlNamedElementList<Property>();
}
public XmlNamedElementList<Property> Properties { get; set; }
}
public static class TestClass
{
public static void Test()
{
var root = new RootObject
{
// Characters " <> first" in the first element name are for testing purposes.
Properties = new XmlNamedElementList<Property> { new Property { id = 1, value = "1", name = "first" }, new Property("property1name", 2, "testvalue"), new Property("property2name", 10, "anothervalue") }
};
var xml = root.GetXml();
Debug.WriteLine(xml);
}
}
Which produces XML as follows:
<?xml version="1.0" encoding="utf-16"?>
<RootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Properties>
<_x0020__x003C__x003E__x0020_first>
<id>1</id>
<value>1</value>
</_x0020__x003C__x003E__x0020_first>
<property1name>
<id>2</id>
<value>testvalue</value>
</property1name>
<property2name>
<id>10</id>
<value>anothervalue</value>
</property2name>
</Properties>
</RootObject>
Original Answer
As requested, here's an implementation of IXmlSerializable on a List<KeyValuePair<string, T>> in which the Key string becomes the element name in the collection.
What you would probably want to do is to adapt this to serialize a List<IHasElementName> where:
public interface IHasElementName
{
string ElementName { get; set; }
}
public class Property : IHasElementName
{
[XmlIgnore]
public string name; //could be enum
public int id;
public string value;
#region IHasElementName Members
[XmlIgnore]
string IHasElementName.ElementName
{
get
{
return name;
}
set
{
name = value;
}
}
#endregion
}
If the name is actually an Enum, you could return the enum string representation from HasElementName.ElementName.
The list looks like:
public class XmlKeyValueList<T> : List<KeyValuePair<string, T>>, IXmlSerializable
{
// TODO: validate that the "Key" string using XmlConvert.VerifyName.
// https://msdn.microsoft.com/en-us/library/System.Xml.Serialization.XmlSerializer%28v=vs.110%29.aspx
// Any serializer created with the "XmlSerializer(typeof(T), rootAttribute)" must be cached
// to avoid resource & memory leaks.
class ValueSerializerCache
{
// By using a nested class with a static constructor, we defer generation of the XmlSerializer until it's actually required.
static ValueSerializerCache()
{
var rootAttribute = new XmlRootAttribute();
rootAttribute.ElementName = ValueTypeName;
rootAttribute.Namespace = ValueTypeNamespace;
serializer = new XmlSerializer(typeof(T), rootAttribute);
}
static readonly XmlSerializer serializer;
internal static XmlSerializer Serializer { get { return serializer; } }
}
static string ValueTypeName { get { return typeof(T).DefaultXmlElementName(); } }
static string ValueTypeNamespace { get { return typeof(T).DefaultXmlElementNamespace(); } }
#region IXmlSerializable Members
XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
var typeName = ValueTypeName;
reader.ReadStartElement(); // Advance to the first sub element of the list element.
while (reader.NodeType == XmlNodeType.Element)
{
var name = reader.Name;
using (var subReader = reader.ReadSubtree())
{
var doc = XDocument.Load(subReader);
if (doc != null && doc.Root != null)
{
doc.Root.Name = typeName;
using (var docReader = doc.CreateReader())
{
var obj = ValueSerializerCache.Serializer.Deserialize(docReader);
if (obj != null)
{
Add(new KeyValuePair<string, T>(name, (T)obj));
}
}
}
}
// Move past the XmlNodeType.Element
if (reader.NodeType == XmlNodeType.EndElement)
reader.Read();
}
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
foreach (var pair in this)
{
XDocument doc = new XDocument();
using (var subWriter = doc.CreateWriter())
{
// write xml into the writer
ValueSerializerCache.Serializer.Serialize(subWriter, pair.Value);
}
if (doc.Root == null)
continue;
doc.Root.Name = pair.Key;
// Remove redundant namespaces.
foreach (var attr in doc.Root.Attributes().ToList())
{
if (!attr.IsNamespaceDeclaration || string.IsNullOrEmpty(attr.Value))
continue;
if (writer.LookupPrefix(attr.Value) == attr.Name.LocalName)
attr.Remove();
}
doc.Root.WriteTo(writer);
}
}
#endregion
}
public static class XmlSerializationHelper
{
public static string DefaultXmlElementName(this Type type)
{
var xmlType = type.GetCustomAttribute<XmlTypeAttribute>();
if (xmlType != null && !string.IsNullOrEmpty(xmlType.TypeName))
return xmlType.TypeName;
var xmlRoot = type.GetCustomAttribute<XmlRootAttribute>();
if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.ElementName))
return xmlRoot.ElementName;
return type.Name;
}
public static string DefaultXmlElementNamespace(this Type type)
{
var xmlType = type.GetCustomAttribute<XmlTypeAttribute>();
if (xmlType != null && !string.IsNullOrEmpty(xmlType.Namespace))
return xmlType.Namespace;
var xmlRoot = type.GetCustomAttribute<XmlRootAttribute>();
if (xmlRoot != null && !string.IsNullOrEmpty(xmlRoot.Namespace))
return xmlRoot.Namespace;
return string.Empty;
}
}
If UnitItem is changed into
public class UnitItem
{
public string AAA;
public string BBB;
}
then the XML will be
<Items>
<UnitItem>
<AAA>testa</AAA>
<BBB>testb</BBB>
</UnitItem>
</Items>
I want to serialize like this
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
</urlset>
But wrong result generated.
My class is here
[Serializable]
[XmlRoot("urlset")]
public class GoogleSiteMap
{
public GoogleSiteMap() {
xmlns = "http://www.sitemaps.org/schemas/sitemap/0.9";
xmlnsNews = "http://www.google.com/schemas/sitemap-news/0.9";
Urls = new List<gUrlBase>();
}
[XmlAttribute]
public string xmlns { get; set; }
[XmlAttribute("news",Namespace="xmlns")]
public string xmlnsNews { get; set; }
[XmlElement("url")]
public List<gUrlBase> Urls { get; set; }
}
Serializer is here
public static void GenerateGoogle(GoogleSiteMap smap,string filePath) {
XmlSerializer ser = new XmlSerializer(typeof(GoogleSiteMap));
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
ser.Serialize(fs, smap);
fs.Close();
}
}
Then result is here
<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:d1p1="xmlns" d1p1:news="http://www.google.com/schemas/sitemap-news/0.9"/>
What's wrong on my class declaration?
Another QUESTION 2
How can i declare like this
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
<url>
<loc>http://www.example.org/business/article55.html</loc>
<news:news></news:news>
</url>
<url>
<loc>http://www.example.org/business/page1.html</loc>
<lastmod>2010-10-10</lastmod>
<changefreq>weekly</changefreq>
</url>
</urlset>
my declaration is here
[XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
public class GoogleSiteMap
{
public GoogleSiteMap()
{
Urls = new List<gUrlBase>();
}
//[XmlElement("url")]
[XmlElement("url",Type = typeof(gNormalUrl))]
[XmlElement("url",Type = typeof(gNewsUrl))]
public List<gUrlBase> Urls { get; set; }
}
This is return error
The XML element 'url' from namespace 'http://www.sitemaps.org/schemas/sitemap/0.9' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.
How can i declare Same root name "url"?
You need to use the right namespace:
[XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
you can take away xmlns and xmlnsNews properties - they do something else. Likewise, any data in ""http://www.google.com/schemas/sitemap-news/0.9" will need to be marked as such. Whether the namespace alias is news is irrelevant (it is only an alias), but that can be controlled via XmlSerializerNamespaces if you like. You do not need [Serializable].
For example, if each <url> needs to be in the "http://www.google.com/schemas/sitemap-news/0.9" namespace, and you want to use "http://www.sitemaps.org/schemas/sitemap/0.9" as the overall namespace and "http://www.google.com/schemas/sitemap-news/0.9" aliased as "news", then:
static class Program
{
static void Main()
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "http://www.sitemaps.org/schemas/sitemap/0.9");
ns.Add("news", "http://www.google.com/schemas/sitemap-news/0.9");
var ser = new XmlSerializer(typeof (GoogleSiteMap));
var obj = new GoogleSiteMap {Urls = new List<string> {"abc", "def", "ghi"}};
ser.Serialize(Console.Out, obj, ns);
}
}
[XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
public class GoogleSiteMap
{
[XmlElement("url", Namespace = "http://www.google.com/schemas/sitemap-news/0.9")]
public List<string> Urls { get; set; }
}
This generates:
<urlset
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<news:url>abc</news:url>
<news:url>def</news:url>
<news:url>ghi</news:url>
</urlset>
(I haven't checked what the actual content namespaces are - this is just to show the relationship between namespaces in the data, namespaces in the xml, and namespace-aliases)
Re your edit - something like:
static class Program
{
static void Main()
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "http://www.sitemaps.org/schemas/sitemap/0.9");
ns.Add("news", "http://www.google.com/schemas/sitemap-news/0.9");
var ser = new XmlSerializer(typeof (GoogleSiteMap));
var obj = new GoogleSiteMap {Urls = {
new SiteUrl { Location = "http://www.example.org/business/article55.html", News = ""},
new SiteUrl { Location = "http://www.example.org/business/page1.html", LastModified = new DateTime(2010,10,10),
ChangeFrequency = "weekly"}
}};
ser.Serialize(Console.Out, obj, ns);
}
}
[XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
public class GoogleSiteMap
{
private readonly List<SiteUrl> urls = new List<SiteUrl>();
[XmlElement("url")]
public List<SiteUrl> Urls { get { return urls; } }
}
public class SiteUrl
{
[XmlElement("loc")]
public string Location { get; set; }
[XmlElement("news", Namespace = "http://www.google.com/schemas/sitemap-news/0.9")]
public string News { get; set; }
[XmlElement("lastmod")]
public DateTime? LastModified { get; set; }
[XmlElement("changefreq")]
public string ChangeFrequency { get; set; }
public bool ShouldSerializeLastModified() { return LastModified.HasValue; }
}
which generates:
<urlset xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.example.org/business/article55.html</loc>
<news:news />
</url>
<url>
<loc>http://www.example.org/business/page1.html</loc>
<lastmod>2010-10-10T00:00:00</lastmod>
<changefreq>weekly</changefreq>
</url>
</urlset>
Please use below full code that made by me
Please see below full code
#region GoogleNewsSiteMap Class
[XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
public class GoogleNewsSiteMap
{
const string _newsSiteMapSchema = "http://www.google.com/schemas/sitemap-news/0.9";
const string _newsSiteMapPrefix = "n";
public void Create(string loc, string prioity, string language, string name, string genres, string publicationDate, string title)
{
NewsSiteMap news = new NewsSiteMap();
news.Loc = loc;
news.Priority = prioity;
news.NewsSiteMapNews.Publication.Language = language;
news.NewsSiteMapNews.Publication.Name = name;
news.NewsSiteMapNews.Genres = genres;
news.NewsSiteMapNews.PublicationDate = publicationDate;
news.NewsSiteMapNews.Title = title;
List.Add(news);
}
public string GetXMLString()
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = (" ");
settings.Encoding = new UTF8Encoding(false);
using (StringWriter str = new StringWriter())
using (XmlWriter writer = XmlWriter.Create(str, settings))
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(_newsSiteMapPrefix, _newsSiteMapSchema);
XmlSerializer xser = new XmlSerializer(typeof(GoogleNewsSiteMap));
xser.Serialize(writer, this, ns);
return str.ToString();
}
}
private List<NewsSiteMap> _list = null;
[XmlElement("url")]
public List<NewsSiteMap> List
{
get
{
if (_list == null)
{
_list = new List<NewsSiteMap>();
}
return _list;
}
}
#region NewsSiteMap Class
public class NewsSiteMap
{
private string _loc = string.Empty;
private string _priority = string.Empty;
private NewsSiteMap_News _newsSiteMap_News = null;
[XmlElement("loc")]
public string Loc
{
get { return _loc; } set { _loc = value; }
}
[XmlElement("priority")]
public string Priority
{
get { return _priority; } set { _priority = value; }
}
[XmlElement("news", Namespace = _newsSiteMapSchema)]
public NewsSiteMap_News NewsSiteMapNews
{
get {
if (_newsSiteMap_News == null)
{
_newsSiteMap_News = new NewsSiteMap_News();
}
return _newsSiteMap_News;
}
set { _newsSiteMap_News = value; }
}
#region NewsSiteMap_News Class
public class NewsSiteMap_News
{
private NewsSiteMap_Publication _publication = null;
private string _genres = string.Empty;
private string _publicationDate = string.Empty;
private string _title = string.Empty;
private string _keywords = string.Empty;
private string _stockTickers = string.Empty;
[XmlElement("publication", Namespace = _newsSiteMapSchema)]
public NewsSiteMap_Publication Publication
{
get
{
if (_publication == null)
{
_publication = new NewsSiteMap_Publication();
}
return _publication;
}
set { _publication = value; }
}
[XmlElement("genres")]
public string Genres
{
get { return _genres; }
set { _genres = value; }
}
[XmlElement("publication_date")]
public string PublicationDate
{
get
{
try
{
return string.Format("{0:s}", Convert.ToDateTime(_publicationDate)) + string.Format("{0:zzz}", Convert.ToDateTime(_publicationDate));
}
catch (Exception ex)
{
return _publicationDate;
}
}
set { _publicationDate = value; }
}
public string Title
{
set { _title = value; }
}
[XmlElement("title")]
public XmlCDataSection CTitle
{
get
{
XmlDocument doc = new XmlDocument();
return doc.CreateCDataSection(_title);
}
set { _title = value.Value; }
}
[XmlElement("keywords")]
public string Keywords
{
get { return _keywords; } set { _keywords = value; }
}
[XmlElement("stock_tickers")]
public string StockTickers
{
get { return _stockTickers; } set { _stockTickers = value; }
}
#region NewsSiteMap_Publication Class
public class NewsSiteMap_Publication
{
private string _name = string.Empty;
private string _language = string.Empty;
[XmlElement("name")]
public string Name
{
get { return _name; }
set { _name = value; }
}
[XmlElement("language")]
public string Language
{
get { return _language; }
set { _language = value; }
}
}
#endregion NewsSiteMap_Publication Class
}
#endregion NewsSiteMap_News Class
}
#endregion NewsSiteMap Class
}
#endregion GoogleNewsSiteMap Class
Usage
Response.Clear();
Response.ContentType = "text/xml";
Response.ContentEncoding = System.Text.Encoding.UTF8;
GoogleNewsSiteMap googleNewsSiteMap = new GoogleNewsSiteMap();
googleNewsSiteMap.Create(/*put ur data*/);
Response.Write(googleNewsSiteMap.GetXMLString());
This is my code so far:
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Xml;
namespace Opgaver
{
class OpgaveController
{
static ArrayList _arrAktiveOpgaver = new ArrayList();
public ArrayList arrAktiveOpgaver
{
get { return _arrAktiveOpgaver; }
set { _arrAktiveOpgaver = value; }
}
static ArrayList _arrAfsluttedeOpgaver = new ArrayList();
public ArrayList arrAfsluttedeOpgaver
{
get { return _arrAfsluttedeOpgaver; }
set { _arrAfsluttedeOpgaver = value; }
}
static int _opgavenr = 100;
public int opgavenr
{
get { return _opgavenr; }
set { _opgavenr = value; }
}
public void opretOpgave(string opgavenavn, string opgavebeskrivelse, int opgaveprioritet, DateTime opgaveafsluttetdato)
{
DateTime oprettetdato = new DateTime();
oprettetdato = DateTime.Now;
bool opgaveafsluttet = false;
Opgave opgave = new Opgave(oprettetdato, _opgavenr, opgavenavn, opgavebeskrivelse, opgaveprioritet, opgaveafsluttet, opgaveafsluttetdato);
if (opgave.opgaveAfsluttet == false)
{
_arrAktiveOpgaver.Add(opgave);
}
else
{
_arrAfsluttedeOpgaver.Add(opgave);
}
_opgavenr++;
}
public OpgaveController()
{
}
}
public void test()
{
string outfile = #"C:\Folder\Tester.xml";
XmlSerializer xs;
Serialize<List<Opgave>>(arrAktiveOpgaver, outfile);
arrAktiveOpgaver = <List<Opgave>>(outfile);//deserialize data - Generates this error: Error 2 Using the generic type 'System.Collections.Generic.List<T>' requires 1 type arguments P:\Programmerings opgaver\Opgaver\Opgaver\OpgaveController.cs 107 33 Opgaver
}
private void Serialize<T1>(ArrayList arrAktiveOpgaver, string outfile)
{
throw new NotImplementedException();
}
public static T DeserializeFromXml<T>(string inputFile)
{
XmlSerializer s = new XmlSerializer(typeof(T));
T deserializedObject = default(T);
using (TextReader textReader = new StreamReader(inputFile))
{
deserializedObject = (T)s.Deserialize(textReader);
textReader.Close();
}
return deserializedObject;
}
public static void SerializeToXml<T>(T objToSerialize, string outputFile)
{
XmlSerializer s = new XmlSerializer(objToSerialize.GetType());
using (TextWriter textWriter = new StreamWriter(outputFile))
{
s.Serialize(textWriter, objToSerialize);
textWriter.Close();
}
}
}
}
i need to serialize the arraylist, and deserialize it..
and here is my opgave class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Opgaver
{
[Serializable()] public class Opgave : IComparable
{
DateTime _oprettetDato = new DateTime();
public DateTime oprettetDato
{
get { return _oprettetDato; }
set { _oprettetDato = value; }
}
int _opgavenr;
public int opgavenr
{
get { return _opgavenr; }
set { _opgavenr = value; }
}
string _opgaveNavn;
public string opgaveNavn
{
get { return _opgaveNavn; }
set { _opgaveNavn = value; }
}
string _opgaveBeskrivelse;
public string opgaveBeskrivelse
{
get { return _opgaveBeskrivelse; }
set { _opgaveBeskrivelse = value; }
}
int _opgavePrioritet;
public int opgavePrioritet
{
get { return _opgavePrioritet; }
set { _opgavePrioritet = value; }
}
bool _opgaveAfsluttet = false;
public bool opgaveAfsluttet
{
get { return _opgaveAfsluttet; }
set { _opgaveAfsluttet = value; }
}
DateTime _opgaveAfsluttetDato = new DateTime();
public DateTime opgaveAfsluttetDato
{
get { return _opgaveAfsluttetDato; }
set { _opgaveAfsluttetDato = value; }
}
public Opgave()
{
}
public Opgave(DateTime oprettetdato, int opgavenr, string opgavenavn, string opgavebeskrivelse, int opgaveprioritet, bool opgaveafsluttet, DateTime opgaveafsluttetdato)
{
_oprettetDato = oprettetdato;
_opgavenr = opgavenr;
_opgaveNavn = opgavenavn;
_opgaveBeskrivelse = opgavebeskrivelse;
_opgavePrioritet = opgaveprioritet;
_opgaveAfsluttet = opgaveafsluttet;
_opgaveAfsluttetDato = opgaveafsluttetdato;
}
//Sorterings metode
public int CompareTo(object obj)
{
Opgave Compare = (Opgave)obj;
int result = this.opgavenr.CompareTo(Compare.opgavenr);
if (result == 0)
result = this.opgavenr.CompareTo(Compare.opgavenr);
return result;
}
}
}
Use this static methods whenver you want to serialize or deserialize data:
example:
public void test()
{
string outfile = #"C:\Folder\Tester.xml";
SerializeToXml<List<Opgaver>>(arrAktiveOpgaver, outfile);//serialize data
arrAktiveOpgaver = DeserializeFromXml<List<Opgaver>>(outfile);//deserialize data
}
public static T DeserializeFromXml<T>(string inputFile)
{
XmlSerializer s = new XmlSerializer(typeof(T));
T deserializedObject = default(T);
using (TextReader textReader = new StreamReader(inputFile))
{
deserializedObject = (T)s.Deserialize(textReader);
textReader.Close();
}
return deserializedObject;
}
public static void SerializeToXml<T>(T objToSerialize, string outputFile)
{
XmlSerializer s = new XmlSerializer(objToSerialize.GetType());
using (TextWriter textWriter = new StreamWriter(outputFile))
{
s.Serialize(textWriter, objToSerialize);
textWriter.Close();
}
}
Serialize array of Opgave instead of serializing them in loop.
XmlSerializer xs = new XmlSerializer(arrAktiveOpgaver.GetType());
xs.Serialize(sw, arrAktiveOpgaver);
And then deserialize as array of Opgave.