Write XML without CData - c#

I want to write XML, and the output is below part in XML like ..<abc><![CDATA[stackoverflow]]></abc>..
[XmlIgnore]
public string abc { get; set; }
[XmlElement("abc")]
public System.Xml.XmlCDataSection abc_NoCDATA
{
get
{
return new System.Xml.XmlDocument().CreateCDataSection(abc);
}
set
{
abc = value.Value;
}
}
How can I write XML without CDATA?

You're explicitly returning an XmlCDataSection, this doesn't make sense if you don't want one.
Simply make abc the actual XmlElement that you output. This should be suffice:
[XmlElement("abc")]
public string abc { get; set; }
If you want more control, consider using XmlDocument or XDocument classes directly to create your XML Document from the start, rather than serialization.

Related

Control the order of attributes when serialising

Let me start off by saying I've seen the following questions:
Controlling order of serialization in C#: It is about element order
How to specify the order of XmlAttributes, using XmlSerializer: The answer just says "You don't"
net xmlserializer : keeping attributes order: Again says "you don't" or the alternate answer states that you can but you have to do all of the serialisation yourself
I've also seen people state that the order that you specify the attributes in the class is the order that they will be serialised. However, in my case I have a base class that has attributes too so this doesn't seem to work out.
I have the following two classes:
public class MyClass : BaseClass
{
[XmlAttribute()]
public string Value1 { get; set; }
public MyClass()
: base()
{
Value1 = string.Empty;
}
}
public class BaseClass
{
[XmlAttribute()]
public string Value2 { get; set; }
[XmlAttribute()]
public string Value3 { get; set; }
public BaseClass()
{
Value2 = string.Empty;
Value3 = string.Empty;
}
}
When serialised to an XML element's attributes they appear in the order, Value2, Value3, Value1. I'd like them to appear in the order Value1, Value2, Value3.
I use the following method to save the XML to disk:
public static void Save<T>(string path, T contents)
{
using (StreamWriter sw = new StreamWriter(File.OpenWrite(path)))
{
XmlSerializer xml = new XmlSerializer(typeof(T));
xml.Serialize(sw, contents, ns);
}
}
Is there any way I can specify the attribute order? Like with elements:
[XmlElementAttribute(Order = 1)]
To those who will say something like "Order doesn't matter" or "If it works why do you need to change the order" or "XML isn't meant to be readable". My answer is yes the order doesn't matter and it works. However, when I'm debugging my code and checking the XML to make sure it contains the values I expect, it is a lot easier to read if the attributes are in the order I want them to be in.

How to deserialize a tag nested within a text section of another tag?

How to represent the structure of the following XML for its further deserialization into classes?
<HeadElement id="1">
Text in HeadElement start
<SubElement samp="0">
Text in SubElement
</SubElement>
Continue text
</HeadElement>
My current code looks like this:
[DataContract]
public class ClaimText
{
[DataMember, XmlElement(ElementName = "claim-ref")]
public ClaimRef claimref; // { get; private set; }
public void setclaimref(ClaimRef claimref_)
{
this.claimref = claimref_;
}
[DataMember, XmlText()]
public string txt; // { get; private set; }
public void settxt(string txt_)
{
this.txt = txt_;
}
}
Given the following XML contents:
<claim id="CLM-00016" num="00016">
<claim-text>16. The midgate assembly of <claim-ref idref="CLM-00015">claim 15</claim-ref>, further comprising a second ramp member connected to an opposite side of the midgate panel for selectively covering an opposite end of the pass-through aperture. </claim-text>
</claim>
I get the object in which the link to the "claim-ref" is present, but not the entire text: only the second part of it (", further comprising ..."). How to get the whole text?
First of all you are mixing attributes for DataContractSerializer and XmlSerializer.
Ad rem: in case of mixed elements it's better to use XmlSerializer. Here is the structure that works with your XML:
[XmlRoot(ElementName = "claim")]
public class ClaimText
{
[XmlAttribute]
public string id;
[XmlAttribute]
public string num;
[XmlElement(ElementName = "claim-text")]
public ClaimInnerContents contents;
}
public class ClaimInnerContents
{
[XmlElement(ElementName = "claim-ref", Type = typeof(ClaimRef))]
[XmlText(Type = typeof(string))]
public object[] contents;
}
public class ClaimRef
{
[XmlAttribute]
public string idref;
[XmlText]
public string text;
}
ClaimRef and splitted text sections are deserialized into contents array as objects.
You can (and should) of course provide statically typed and checked accessors to particular elements of this array.

What are XML element and attribute equivalents in C#?

I am trying to define C# objects based on this XML:
<UPDs LUPD="86">
<UPD ID="106">
<ER R="CREn">
<NU UID="1928456" />
<NU UID="1886294" />
<M>
<uN>bob ยท </uN>
<mO>fine :D</mO>
</M>
So far I have:
public class UDPCollection
{
List<UDP> UDPs;
public UDPCollection()
{
UDPs = new List<UDP>();
}
}
public class UDP
{
public int Id;
public List<ER> ERs;
public UDP(int id, List<ER> ers)
{
Id = id;
ERs = ers;
}
}
public class ER
{
public string LanguageR;
public ER(string languager)
{
LanguageR = languager;
}
}
My questions: What do elements map to in C#? Classes? What do attributes map to? Properties? Am I going about this the correct way?
Use the XmlSerializer class and the XmlRoot, XmlElement and XmlAttribute attributes. For example:
using System.Xml.Serialization;
...
[XmlRoot("UPDs")]
public class UDPCollection
{
// XmlSerializer cannot serialize List. Changed to array.
[XmlElement("UPD")]
public UDP[] UDPs { get; set; }
[XmlAttribute("LUPD")]
public int LUPD { get; set; }
public UDPCollection()
{
// Do nothing
}
}
[XmlRoot("UPD")]
public class UDP
{
[XmlAttribute("ID")]
public int Id { get; set; }
[XmlElement("ER")]
public ER[] ERs { get; set; }
// Need a parameterless or default constructor.
// for serialization. Other constructors are
// unaffected.
public UDP()
{
}
// Rest of class
}
[XmlRoot("ER")]
public class ER
{
[XmlAttribute("R")]
public string LanguageR { get; set; }
// Need a parameterless or default constructor.
// for serialization. Other constructors are
// unaffected.
public ER()
{
}
// Rest of class
}
The code to write out the XML is:
using System.Xml.Serialization;
...
// Output the XML to this stream
Stream stream;
// Create a test object
UDPCollection udpCollection = new UDPCollection();
udpCollection.LUPD = 86;
udpCollection.UDPs = new []
{
new UDP() { Id= 106, ERs = new [] { new ER() { LanguageR = "CREn" }}}
};
// Serialize the object
XmlSerializer xmlSerializer = new XmlSerializer(typeof(UDPCollection));
xmlSerializer.Serialize(stream, udpCollection);
Not that the XmlSerializer adds additional namepsaces but it can parse XML without them if needed. The output of the above is:
<?xml version="1.0"?>
<UPDs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" LUPD="86">
<UPD ID="106">
<ER R="CREn" />
</UPD>
</UPDs>
Use the Deserialize() method to parse it from XML into an object.
XML elements and attributes don't necessarily map to anything in particular in C#. You can make them map to classes and properties if you want, but it's not required.
That said, if you want to map your existing XML to some sort of C# data structures, the way you're doing it seems reasonable - I'd just recommend replacing your public fields with actual properties, and maybe making the list properties a less specific type - say, IEnumerable, or ICollection, or IList if they really need to be in order.

C# XmlSerializer: keep the value, override the element label

I am currently using a LINQ query to read an XML file e.g.
<MyObjects>
<MyObject>
<MyElement>some_text</MyElement>
<MyOtherElement>some_more_text</MyOtherElement>
</MyObject>
</MyObjects>
into a list of custom objects containing custom HistoryString properties. HistoryString contains 2 strings, a currentValue and a previousValue.
This all works great except when using XmlSerializer to write the custom objects back to an XML file, the output fairly obviously contains additional tags i.e.
<MyObjects>
<MyObject>
<MyElement>
<currentValue>some_text</currentValue>
<previousValue>some_text</previousValue>
</MyElement>
<MyOtherElement>
<currentValue>some_more_text</currentValue>
<previousValue>some_more_text</previousValue>
</MyOtherElement>
</MyObject>
</MyObjects>
Q: What would be the neatest and/or most efficient way of reading and writing XML in the same format, based on this fundamental difference?
Some initial ideas:
1) Mark the previousValue property with [System.Xml.Serialization.XmlIgnore] then sweep through the XML string that is to be written removing all traces of <currentValue> and </currentValue>
2) Open the existing file and manually make any updates/deletes/additions - this is surely more long winded.
3) Any way of having a HistoryString automatically resolve to its currentValue rather than serialize each of its properties, similar to how ToString() works?
I have done some research into this, including the useful MSDN articles here and here but I can't see any other attributes that would solve this problem, I am still unsure whether this is possible. Any ideas?
Here is another idea. If you define your class like so:
[Serializable]
public class MyObject
{
[XmlElement(ElementName = "MyElement")]
public string CurrentValueElement
{
get
{
return Element.CurrentValue;
}
set
{
Element = new MyElement
{
CurrentValue = value, PreviousValue = value
};
}
}
[XmlElement(ElementName = "MyOtherElement")]
public string CurrentValueOtherElement
{
get
{
return OtherElement.CurrentValue;
}
set {}
}
[XmlIgnore]
public MyElement Element { get; set; }
[XmlIgnore]
public MyElement OtherElement { get; set; }
}
Then, when the object is serialized, the output XML will look exactly like your example.
Also, if you extend the CurrentValueElement/CurrentValueOtherElement setter like this:
[XmlElement(ElementName = "MyElement")]
public string CurrentValueElement
{
get
{
return Element.CurrentValue;
}
set
{
Element = new MyElement
{
CurrentValue = value, PreviousValue = value
};
}
}
Then you'll be able to use the XmlSerializer to deserialize your objects directly without needing to resorting to LINQ.
Well why not serialize back using original schema and feeding into it the list of transformed objects from history using only current value?
e.g.
from h in HistoryEntryList
select new OriginalEntry{ field = h.field.current_value, ... };

IXmlSerializable

Could you guys help me I have a problem with deserialization via IXmlSerializable
var ArrayOfAccounts = new Accounts(); //This class structure I'm trying to read
Class Accounts:List<Session>{ }
Class Shedule{
public DateTime StartAt { get; set; }
public DateTime EndAt { get; set; }
}
Class Session:IXmlSerializable {
public string Name{get;set;}
public string Pass{get;set;}
public List<Shedule> Shedules = new List<Shedule>();
public void ReadXml(System.Xml.XmlReader reader){
//AND HERE IS A PROBLEM. I don't know how to implement right code here. I've tried
//code below, but this one works for the first account only, and doesn't restore others
Schedules.Clear();
XmlReader subR = reader.ReadSubtree();
if (reader.MoveToAttribute("Name"))
Name = reader.Value;
if (reader.MoveToAttribute("Password"))
Password = reader.Value;
reader.MoveToContent();
while (subR.ReadToFollowing("Schedule"))
{
XmlSerializer x = new XmlSerializer(typeof(Schedule));
object o = x.Deserialize(subR);
if (o is Schedule) Schedules.Add((Schedule)o);
}
}
And the xml itself looks like:
<Accounts>
<Session UserName="18SRO" Password="shalom99">
<Schedule>
<StartAt>0001-01-01T09:30:00</StartAt>
<EndAt>0001-01-01T16:00:00</EndAt>
</Schedule>
</Session>
</Accounts>
Since you've defined the classes, you should just be able to use XML Serialization attributes, and use the default XML deserializer.
Your structure doesn't look overly complicated, is there any particular reason you're not using serialization attributes instead of manually deserializing?
Re inherited fields... if you switch to DataContractSerializer, then fields are "opt in" rather than "opt out" - but you lose the ability to specify attributes (everything is an element). A trivial example:
[DataContract(Name="foo")]
public class Foo
{
[DataMember(Name="bar")]
public string Bar { get; set; }
public int ThisIsntSerialized {get;set;}
}
However - adding unexpected subclasses is a pain for both XmlSerializer and DataContractSerializer. Both can do it, but it isn't pretty...

Categories

Resources