XML namespaces for sub class in c# - c#

I need to create xml with certain looks using serializer:
EPIT11V21 curpit11 = new EPIT11V21(curdec.id);
XmlSerializer serializer = new XmlSerializer(typeof(EPIT11V21));
using (TextWriter writer = new StreamWriter(#"F:\xml\Xml.xml"))
{
serializer.Serialize(writer, curpit11);
}
where my EPIT11V21 class is declared:
[XmlRoot("Deklaracja")]
public class EPIT11V21
{
public EPIT11V21() { }
public EPIT11V21(int XPDeclarationID)
{
this.Pouczenie = "Za uchybienie obowiązkom płatnika grozi odpowiedzialność przewidziana w Kodeksie karnym skarbowym.";
//this.Zalaczniki = "";
}
}
public Podmiot1PIT11V21 Podmiot1 = new Podmiot1PIT11V21();
public String Pouczenie { get; set; }
public String Zalaczniki{ get; set; }
with subclasses:
public class Podmiot1PIT11V21
{
public Podmiot1PIT11V21(){}
[XmlAttribute("rola")]
public string rola = "Płatnik";
public OsobaNiefizycznaPIT11V21 OsobaNieFizyczna = new OsobaNiefizycznaPIT11V21();
}
public class OsobaNiefizycznaPIT11V21
{
public OsobaNiefizycznaPIT11V21(){}
public string NIP = "0000000000";
public string PelnaNazwa = "XXXXXXXX";
}
How to decorate its parts to get such an effect:
<?xml version="1.0" encoding="UTF-8"?>
<Deklaracja xsi:schemaLocation="http://crd.gov.pl/wzor/2014/12/08/1887/ http://crd.gov.pl/wzor/2014/12/08/1887/schemat.xsd" xmlns="http://crd.gov.pl/wzor/2014/12/08/1887/" xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/06/21/eD/DefinicjeTypy/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:zzu="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/10/07/eD/ORDZU/">
<Podmiot1 rola="Płatnik">
<etd:OsobaNiefizyczna>
<etd:NIP>0000000000</etd:NIP>
<etd:PelnaNazwa>XXXXXXXXXXXXX</etd:PelnaNazwa>
</etd:OsobaNiefizyczna>
</Podmiot1>
<Zalaczniki>
</Zalaczniki>
</Deklaracja>
i just get in second line:
<Deklaracja xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
also how to decorate that clasess so to get etd: prefix as in example ??

Your question has many different components:
In order to make the property OsobaNiefizyczna go in the correct namespace, decorate it with XmlElement and set the Namespace property correctly.
In order to add additional namespaces to the root document object, attach the [XmlNamespaceDeclarations] attribute to a public XmlSerializerNamespaces xmlsn synthetic property returning the namespaces. Also set the XmlRootAttribute.Namespace properly on the root object.
To make the root object have a schemaLocation attribute, you must add a synthetic property along the lines of the answer in How to add xsi schemalocation to root c # object XmlSerializer -- but use a property instead of a field. If you use a field you will actually add to the footprint of your class in memory.
To omit the standard xsd namespace (though I recommend you do not), use the XmlSerializer.Serialize(XmlWriter, Object, XmlSerializerNamespaces) method and pass in only the namespaces you want to see.
To make an empty Zalaczniki element show up, you need to set the property value to string.Empty.
Putting these together we get:
public static class NameSpaces
{
static readonly XmlSerializerNamespaces namespaces;
static NameSpaces()
{
namespaces = new XmlSerializerNamespaces();
namespaces.Add("", NameSpaces.Default);
namespaces.Add("xsi", NameSpaces.Xsi);
namespaces.Add("etd", NameSpaces.Etd);
namespaces.Add("zzu", NameSpaces.Zzu);
}
public static XmlSerializerNamespaces XmlSerializerNamespaces
{
get
{
return namespaces;
}
}
public const string Default = "http://crd.gov.pl/wzor/2014/12/08/1887/";
public const string Etd = "http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/06/21/eD/DefinicjeTypy/";
public const string Xsi = "http://www.w3.org/2001/XMLSchema-instance";
public const string Zzu = "http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/10/07/eD/ORDZU/";
public const string SchemaLocation = "http://crd.gov.pl/wzor/2014/12/08/1887/ http://crd.gov.pl/wzor/2014/12/08/1887/schemat.xsd";
}
[XmlRoot("Deklaracja", Namespace = NameSpaces.Default)]
public class EPIT11V21
{
public EPIT11V21() {
this.Zalaczniki = string.Empty;
}
public EPIT11V21(int XPDeclarationID) : this()
{
this.Pouczenie = "Za uchybienie obowiązkom płatnika grozi odpowiedzialność przewidziana w Kodeksie karnym skarbowym.";
}
[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string XSDSchemaLocation
{
get
{
return NameSpaces.SchemaLocation;
}
set {
// Do nothing - fake property.
}
}
public Podmiot1PIT11V21 Podmiot1 = new Podmiot1PIT11V21();
public String Pouczenie { get; set; }
public String Zalaczniki { get; set; }
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces xmlsn
{
get
{
return NameSpaces.XmlSerializerNamespaces;
}
set {
// Do nothing - fake property.
}
}
}
public class Podmiot1PIT11V21
{
public Podmiot1PIT11V21() { }
[XmlAttribute("rola")]
public string rola = "Płatnik";
[XmlElement("OsobaNieFizyczna", Namespace = NameSpaces.Etd)]
public OsobaNiefizycznaPIT11V21 OsobaNieFizyczna = new OsobaNiefizycznaPIT11V21();
}
public class OsobaNiefizycznaPIT11V21
{
public OsobaNiefizycznaPIT11V21() { }
public string NIP = "0000000000";
public string PelnaNazwa = "XXXXXXXX";
}
And, to test:
public static class TestClass
{
public static void Test()
{
var curpit11 = new EPIT11V21(10101);
var xml = XmlSerializationHelper.GetXml(curpit11, NameSpaces.XmlSerializerNamespaces);
Debug.WriteLine(xml);
}
}
public static class XmlSerializationHelper
{
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();
}
}
}
Produces
<Deklaracja xmlns:zzu="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/10/07/eD/ORDZU/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/06/21/eD/DefinicjeTypy/" xsi:schemaLocation="http://crd.gov.pl/wzor/2014/12/08/1887/ http://crd.gov.pl/wzor/2014/12/08/1887/schemat.xsd" xmlns="http://crd.gov.pl/wzor/2014/12/08/1887/">
<Podmiot1 rola="Płatnik">
<etd:OsobaNieFizyczna>
<etd:NIP>0000000000</etd:NIP>
<etd:PelnaNazwa>XXXXXXXX</etd:PelnaNazwa>
</etd:OsobaNieFizyczna>
</Podmiot1>
<Pouczenie>Za uchybienie obowiązkom płatnika grozi odpowiedzialność przewidziana w Kodeksie karnym skarbowym.</Pouczenie>
<Zalaczniki />
</Deklaracja>

I change my code like this:
Declaration curdec = gVDeclarations.GetRow(i) as Declaration;
EPIT11V21 curpit11 = new EPIT11V21(curdec.id);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("schemaLocation", #"http://crd.gov.pl/wzor/2014/12/08/1887/ http://crd.gov.pl/wzor/2014/12/08/1887/schemat.xsd");
ns.Add("xmlns", #"http://crd.gov.pl/wzor/2014/12/08/1887/");
ns.Add("etd", #"http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/06/21/eD/DefinicjeTypy/");
ns.Add("xsi", #"http://www.w3.org/2001/XMLSchema-instance");
ns.Add("zzu", #"http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/10/07/eD/ORDZU/");
XmlSerializer serializer = new XmlSerializer(typeof(EPIT11V21));
using (TextWriter writer = new StreamWriter(#"F:\xml\Xml.xml"))
{
serializer.Serialize(writer, curpit11,ns);
}
and to Deklaracja sub clases
public class Podmiot1PIT11V21
{
public Podmiot1PIT11V21(){}
[XmlAttribute("rola")]
public string rola = "Płatnik";
[XmlElement("OsobaNieFizyczna", Namespace = "http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/06/21/eD/DefinicjeTypy/")]
public OsobaNiefizycznaPIT11V21 OsobaNieFizyczna = new OsobaNiefizycznaPIT11V21();
}
I get almoast what iwant but 2nd line which i get:
<Deklaracja
xmlns:xmlns="http://crd.gov.pl/wzor/2014/12/08/1887/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:schemaLocation="http://crd.gov.pl/wzor/2014/12/08/1887/ http://crd.gov.pl/wzor/2014/12/08/1887/schemat.xsd"
xmlns:zzu="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/10/07/eD/ORDZU/"
xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2011/06/21/eD/DefinicjeTypy/">
is there a way to just change "ns" to change that line in easy way ?

Related

Wrap properties with CData Section - XML Serialization C#

I need to serialize my object in such a way that the properties I want, would get wrapped around CData sections.
I was hoping I could do something like this :
public class Order
{
[JsonProperty]
public int OrderId { get; set; }
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public int Type { get; set; }
[JsonProperty]
public decimal Amount { get; set; }
[JsonProperty]
public DateTime Date { get; set; }
[DataMember]
[JsonProperty]
**[WrapCData]**
public List<Option> ListB { get; set; }
[DataMember]
public List<string> ListC { get; set; }
**[WrapCData]**
public Product Product { get; set; }
}
Is there any attribute or an implementation which could wrap my specific properties around a CData section? Existing StackOverflow answers suggest fiddling with the Entity(Class) itself. This would get really messy.
In the following thread :
How do you serialize a string as CDATA using XmlSerializer?
Philip's answer suggests to make another property and its corresponding CData property. However the property is a string. CreateCDataSection() also takes a string. I need to wrap my custom objects/lists around CDataSections. How can I do that? Any help would be appreciated. Thanks.
Sample XML for the above Order Class:
<Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<OrderId>2</OrderId>
<Name>Some Name</Name>
<Type>1</Type>
<Amount>100</Amount>
<Date>2015-12-07T15:10:49.6031106+05:00</Date>
<![CDATA[
<ListB>
<Option>
<OptionValue>OptionValue1</OptionValue>
<OptionName>Option1</OptionName>
</Option>
<Option>
<OptionValue>OptionValue2</OptionValue>
<OptionName>Option2</OptionName>
</Option>
</ListB>
]]>
<ListC>
<string>ListItem1</string>
<string>ListItem2</string>
</ListC>
<![CDATA[
<Product>
<ProductId>1</ProductId>
<Name>ProductName</Name>
<Type>Product Type</Type>
</Product>
]]>
</Order>
With some effort and customization, it possible to get close to what you want, however XmlSerializer will always place the CData nodes at the end of the container element. Your example XML shows the CData nodes between specific nodes of the container element. As long as you don't need this precise control, you can use How do you serialize a string as CDATA using XmlSerializer? to do nested serializations, like so:
public class Order
{
[JsonProperty]
public int OrderId { get; set; }
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public int Type { get; set; }
[JsonProperty]
public decimal Amount { get; set; }
[JsonProperty]
public DateTime Date { get; set; }
[DataMember]
[JsonProperty]
[XmlIgnore] // Do not serialize directly
[XmlWrapCData] // Instead include in CDATA nodes
public List<Option> ListB { get; set; }
[DataMember]
public List<string> ListC { get; set; }
[XmlIgnore] // Do not serialize directly
[XmlWrapCData] // Instead include in CDATA nodes
public Product Product { get; set; }
[XmlText] // NECESSARY TO EMIT CDATA NODES
[IgnoreDataMember]
[JsonIgnore]
public XmlNode[] CDataContent
{
get
{
return XmlWrapCDataHelper.GetCDataContent(this);
}
set
{
XmlWrapCDataHelper.SetCDataContent(this, value);
}
}
}
public class Product
{
public string ProductId { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
public class Option
{
public string OptionValue { get; set; }
public string OptionName { get; set; }
}
Using the following extension methods and custom attribute:
[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false)]
public class XmlWrapCDataAttribute : Attribute
{
public XmlWrapCDataAttribute() { this.Namespace = string.Empty; }
public XmlWrapCDataAttribute(string name) : this() { this.Name = name; }
public string Name { get; set; }
public string Namespace { get; set; }
}
public static class XmlWrapCDataHelper
{
static Tuple<PropertyInfo, XmlWrapCDataAttribute> [] XmlWrapCDataProperties(Type type)
{
return type.GetProperties()
.Where(p => p.GetGetMethod() != null && p.GetSetMethod() != null)
.Select(p => Tuple.Create(p, p.GetCustomAttribute<XmlWrapCDataAttribute>()))
.Where(p => p.Item2 != null)
.ToArray();
}
public static XmlNode[] GetCDataContent(object obj)
{
var index = new object[0];
var properties = XmlWrapCDataProperties(obj.GetType());
return properties.Select(p => (XmlNode)p.Item1.GetValue(obj, index).GetCData(p.Item2.Name ?? p.Item1.Name, p.Item2.Namespace)).ToArray();
}
public static void SetCDataContent(object obj, XmlNode [] nodes)
{
if (nodes == null || nodes.Length < 1)
return;
var index = new object[0];
var properties = XmlWrapCDataProperties(obj.GetType()).ToDictionary(p => XName.Get(p.Item2.Name ?? p.Item1.Name, p.Item2.Namespace), p => p);
var xml = "<Root>" + String.Concat(nodes.Select(c => c.Value)) + "</Root>";
foreach (var element in XElement.Parse(xml).Elements())
{
Tuple<PropertyInfo, XmlWrapCDataAttribute> pair;
if (properties.TryGetValue(element.Name, out pair))
{
var value = element.Deserialize(pair.Item1.PropertyType, element.Name.LocalName, element.Name.Namespace.NamespaceName);
pair.Item1.SetValue(obj, value, index);
}
}
}
}
public static class XmlSerializationHelper
{
public static XmlCDataSection GetCData(this object obj, string rootName, string rootNamespace)
{
return obj == null ? null : new System.Xml.XmlDocument().CreateCDataSection(obj.GetXml(XmlSerializerFactory.Create(obj.GetType(), rootName, rootNamespace)));
}
public static XCData GetCData(this object obj, XmlSerializer serializer = null)
{
return obj == null ? null : new XCData(obj.GetXml(serializer));
}
public static string GetXml(this object obj, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
var ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
var settings = new XmlWriterSettings() { Indent = true, IndentChars = " ", OmitXmlDeclaration = true }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
}
}
public static object Deserialize(this XContainer element, Type type, string rootName = null, string rootNamespace = null)
{
return element.Deserialize(type, XmlSerializerFactory.Create(type, rootName, rootNamespace));
}
public static object Deserialize(this XContainer element, Type type, XmlSerializer serializer = null)
{
using (var reader = element.CreateReader())
{
return (serializer ?? new XmlSerializer(type)).Deserialize(reader);
}
}
public static T DeserializeXML<T>(this string xmlString, XmlSerializer serializer = null)
{
using (StringReader reader = new StringReader(xmlString))
{
return (T)(serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
}
}
}
public static class XmlSerializerFactory
{
readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache;
readonly static object padlock;
static XmlSerializerFactory()
{
padlock = new object();
cache = new Dictionary<Tuple<Type, string, string>, XmlSerializer>();
}
public static XmlSerializer Create(Type serializedType, string rootName, string rootNamespace)
{
if (serializedType == null)
throw new ArgumentNullException();
if (rootName == null && rootNamespace == null)
return new XmlSerializer(serializedType);
lock (padlock)
{
XmlSerializer serializer;
var key = Tuple.Create(serializedType, rootName, rootNamespace);
if (!cache.TryGetValue(key, out serializer))
cache[key] = serializer = new XmlSerializer(serializedType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
return serializer;
}
}
}
This will parse your provided XML successfully, and in return generate XML that looks like:
<Order>
<OrderId>2</OrderId>
<Name>Some Name</Name>
<Type>1</Type>
<Amount>100</Amount>
<Date>2015-12-07T05:10:49.6031106-05:00</Date>
<ListC>
<string>ListItem1</string>
<string>ListItem2</string>
</ListC><![CDATA[<ListB>
<Option>
<OptionValue>OptionValue1</OptionValue>
<OptionName>Option1</OptionName>
</Option>
<Option>
<OptionValue>OptionValue2</OptionValue>
<OptionName>Option2</OptionName>
</Option>
</ListB>]]><![CDATA[<Product>
<ProductId>1</ProductId>
<Name>ProductName</Name>
<Type>Product Type</Type>
</Product>]]></Order>

XmlSerializer not deserializing int array

I have the following type:
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
public int Id { get; set; }
public string Name { get; set; }
public Collection<int> DataSourceIds { get; set; }
}
I'm serializing a list of Locations to XML, resulting in the following:
<ArrayOfLocation xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyNamespace">
<Location>
<DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:int>1</d3p1:int>
</DataSourceIds>
<Id>2</Id>
<Name>First</Name>
</Location>
<Location>
<DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:int>1</d3p1:int>
<d3p1:int>2</d3p1:int>
<d3p1:int>3</d3p1:int>
<d3p1:int>4</d3p1:int>
</DataSourceIds>
<Id>1</Id>
<Name>Second</Name>
</Location>
</ArrayOfLocation>
I then try to deserialize this XML as follows:
var rootAttribute = new XmlRootAttribute("ArrayOfLocation")
{
Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace"
};
var serializer = new XmlSerializer(typeof(Location[]), rootAttribute);
using (var xmlReader = XmlReader.Create(new StreamReader(response.GetResponseStream())))
{
locations = (Location[])serializer.Deserialize(xmlReader);
}
This returns a list of Location objects, with every property set correctly... except DataSourceIds, which remains empty. Why isn't XmlSerializer deserializing the array of integers?
Since it was serialized with DataContractSerializer, you can deserialize it like so:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public Collection<int> DataSourceIds { get; set; }
}
And then use it like:
using (var xmlReader = XmlReader.Create(stream))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Location[]));
var locations = (Location[])serializer.ReadObject(xmlReader);
Debug.WriteLine(DataContractSerializerHelper.GetXml(locations, serializer)); // Debug check on re-serialization, remove when not needed.
}
The XmlRoot declaration is ignored by DataContractSerializer.
Finally, a utility method for re-serializing to an XML string, for debugging purposes:
public static class DataContractSerializerHelper
{
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
public static string GetXml<T>(T obj, DataContractSerializer serializer) where T : class
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = " "; // For cosmetic purposes.
using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj);
}
return textWriter.ToString();
}
}
public static string GetXml<T>(T obj) where T : class
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
return GetXml(obj, serializer);
}
}

Serialize type into XML from .NET

I have this C# 4.0 type
public class DecimalField
{
public decimal Value { get; set; }
public bool Estimate { get; set; }
}
I want to use XmlSerializer to serialize the type into
<Val Estimate="true">123</Val>
Ideally, I want to omit the Estimate attribute if its value is false. Changing Estimate to a nullable bool is acceptable.
What attributes/implementations are required to go from this type to this XML representation?
Thanks.
Not sure if you can output Estimate conditionally with attributes only. But you definitelly can implement IXmlSerializable and check Estimate value inside WriteXml method.
Here is an example
Conditionally omitting Estimate would require a lof of coding. I wouldn't go that way.
XmlWriter writer = XmlWriter.Create(stream, new XmlWriterSettings() { OmitXmlDeclaration = true });
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer xml = new XmlSerializer(typeof(DecimalField));
xml.Serialize(writer, obj, ns);
-
[XmlRoot("Val")]
public class DecimalField
{
[XmlText]
public decimal Value { get; set; }
[XmlAttribute]
public bool Estimate { get; set; }
}
You can also manually serialize your class using Linq2Xml
List<XObject> list = new List<XObject>();
list.Add(new XText(obj.Value.ToString()));
if (obj.Estimate) list.Add(new XAttribute("Estimate", obj.Estimate));
XElement xElem = new XElement("Val", list.ToArray());
xElem.Save(stream);
This is about as close as you can get (an Estimate attribute is always included) without implementing IXmlSerializable:
[XmlRoot("Val")]
public class DecimalField
{
[XmlText()]
public decimal Value { get; set; }
[XmlAttribute("Estimate")]
public bool Estimate { get; set; }
}
With IXmlSerializable, your class looks like this:
[XmlRoot("Val")]
public class DecimalField : IXmlSerializable
{
public decimal Value { get; set; }
public bool Estimate { get; set; }
public void WriteXml(XmlWriter writer)
{
if (Estimate == true)
{
writer.WriteAttributeString("Estimate", Estimate.ToString());
}
writer.WriteString(Value.ToString());
}
public void ReadXml(XmlReader reader)
{
if (reader.MoveToAttribute("Estimate") && reader.ReadAttributeValue())
{
Estimate = bool.Parse(reader.Value);
}
else
{
Estimate = false;
}
reader.MoveToElement();
Value = reader.ReadElementContentAsDecimal();
}
public XmlSchema GetSchema()
{
return null;
}
}
You can test your class like this:
XmlSerializer xs = new XmlSerializer(typeof(DecimalField));
string serializedXml = null;
using (StringWriter sw = new StringWriter())
{
DecimalField df = new DecimalField() { Value = 12.0M, Estimate = false };
xs.Serialize(sw, df);
serializedXml = sw.ToString();
}
Console.WriteLine(serializedXml);
using (StringReader sr = new StringReader(serializedXml))
{
DecimalField df = (DecimalField)xs.Deserialize(sr);
Console.WriteLine(df.Estimate);
Console.WriteLine(df.Value);
}

How to serialize google sitemap in c# using XmlSerializer

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());

How do I use XmlSerializer to insert an xml string

I have defined the following class:
public class Root
{
public string Name;
public string XmlString;
}
and created an object:
Root t = new Root
{ Name = "Test",
XmlString = "<Foo>bar</Foo>"
};
When I use XmlSerializer class to serialize this object, it will return the xml:
<Root>
<Name>Test</Name>
<XmlString><Foo>bar</Foo></XmlString>
</Root>
How do I make it not encode my XmlString content so that I can get the serialized xml as
<XmlString><Foo>bar</Foo></XmlString>
Thanks,
Ian
You can limit the custom serialization to just the element that needs special attention like so.
public class Root
{
public string Name;
[XmlIgnore]
public string XmlString
{
get
{
if (SerializedXmlString == null)
return "";
return SerializedXmlString.Value;
}
set
{
if (SerializedXmlString == null)
SerializedXmlString = new RawString();
SerializedXmlString.Value = value;
}
}
[XmlElement("XmlString")]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public RawString SerializedXmlString;
}
public class RawString : IXmlSerializable
{
public string Value { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
this.Value = reader.ReadInnerXml();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteRaw(this.Value);
}
}
You can (ab)use the IXmlSerializable interface an XmlWriter.WriteRaw for that. But as garethm pointed out you then pretty much have to write your own serialization code.
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace ConsoleApplicationCSharp
{
public class Root : IXmlSerializable
{
public string Name;
public string XmlString;
public Root() { }
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("Name", Name);
writer.WriteStartElement("XmlString");
writer.WriteRaw(XmlString);
writer.WriteFullEndElement();
}
public void ReadXml(System.Xml.XmlReader reader) { /* ... */ }
public XmlSchema GetSchema() { return (null); }
public static void Main(string[] args)
{
Root t = new Root
{
Name = "Test",
XmlString = "<Foo>bar</Foo>"
};
System.Xml.Serialization.XmlSerializer x = new XmlSerializer(typeof(Root));
x.Serialize(Console.Out, t);
return;
}
}
}
prints
<?xml version="1.0" encoding="ibm850"?>
<Root>
<Name>Test</Name>
<XmlString><Foo>bar</Foo></XmlString>
</Root>
try this:
public class Root
{
public string Name;
public XDocument XmlString;
}
Root t = new Root
{ Name = "Test",
XmlString = XDocument.Parse("<Foo>bar</Foo>")
};
I would be very surprised if this was possible. Suppose it was possible for you to do this - what would happen if you had malformed XML in the property - everything would just break.
I expect that you will either need to write your own serialization for this case, or make it so that the XmlString field is a structure that contains a foo field.

Categories