I am having a weird issue I am banging my head against...
I have a class like this:
[XmlRoot("DoesntWork")]
class Root
{
[XmlElement(ElementName="WontWork", Order=1)]
public string xmlOutPropertyName
{...}
}
and I am serializing with this:
textBox1.Clear();
Root rt = new Root();
rt.xmlOutPropertyName = "[0000000001]";
XmlSerializer serializer = new XmlSerializer();
textBox1.Text = serializer.Serialize(rt);
but I always get xml that returns the names of class and property and not the name I want.
<Root>
<xmlOutPropertyName>[0000000001]</xmlOutPropertyName>
</Root>
Any idea why this is happening??
Dumb mistake, I was not paying attention and using the wrong serialization library.
Related
I have the following Model in ASP.Net Core
[Serializable]
[XmlRoot(ElementName = "CREDIT")]
public class Credit
{
[XmlElement(ElementName = "D_numbern")]
public string Number get; set; }
}
I did the serialization with StringWriter, the problem I should get XML like that
<CREDITS>
<CREDIT ID="1">
<D_number1>06</D_number1>
</CREDIT>
<CREDIT ID="2">
<D_number2>06</D_number2>
</CREDIT>
</CREDITS>
I didn't find a solution how to make n dynamic for each credit .
thanks in advance for any assistance.
What you're after isn't something that XmlSerializer supports, and frankly it is a bad design for xml generally; not only is it redundant (xml is ordered: there's no need to tell it that you're item 1/2/3), but it is actively hostile to most xml tooling, including serializers, schema validators, etc.
My strong suggestion is to rethink the xml you want, or challenge the requirements if it isn't your idea. If the D_number42 will always match the ID="42" that is the parent, frankly the suffix serves absolutely no purpose. If it is a different number that only looks the same in these examples by coincidence, then: <D_number someattribute="42">06</D_number>
But if you must do this, you'll have to do it manually, via XDocument, XmlDocument, or XmlWriter.
as an example using XmlWriter:
static void WriteCredit(XmlWriter xml, string id, string number)
{
xml.WriteStartElement("CREDITS");
xml.WriteStartElement("CREDIT");
xml.WriteAttributeString("ID", id);
xml.WriteElementString("D_number" + id, number);
xml.WriteEndElement();
xml.WriteEndElement();
}
usage that writes to the console:
using (var xml = XmlWriter.Create(Console.Out))
{
WriteCredit(xml, "1", "06");
}
I would like to Read and Deserialize more than one XML file into my XML class structure given a list of strings consisting of file names.
Obviously when reading ONE xml file, you can go like this:
XmlRoot file = null;
XmlSerializer ser = new XmlSerializer(typeof(XmlRoot));
using (XmlReader read = XmlReader.Create(FileName))
{
file = (XmlRoot)ser.Deserialize(read);
{
Which will deserialize the XML file into the class structure?
It is not possible to have a list with file names and use a foreach loop to iterate over them, reading and deserializing one by one as it would theoretically result into multiple root elements being read, deserialized and replicated in the class structure.
So in general I would like to deserialize each file and append the required master elements to a root object.
Does anyone know how to accomplish this? It would be of great help.
Thanks in advance!
PS: Excuse me for my English, as I am not a native speaker. If you need further information, just tell me!
I managed to solve the problem for myself.
First i created a XDocument for the first file i read, afterwards i iterate through the other documents creating a new XDocument for every xml file and try to get the elements after the root (Language in my case) and add it to the root of the XDocument created outside the loop.
XDocument lDoc = new XDocument();
int counter = 0;
foreach (var fileName in multipleFileNames)
{
try
{
counter++;
if (lCounter <= 1)
{
doc = XDocument.Load(fileName);
}
else
{
XDocument doc2 = XDocument.Load(fileName);
IEnumerable<XElement> elements = doc2.Element("Language")
.Elements();
doc.Root.Add(elements);
}
}
return Deserialize(lDoc);
Afterwards i call the Deserialize method, deserializing my created XDocument like this:
public static XmlLanguage Deserialize(XDocument doc)
{
XmlSerializer ser = new XmlSerializer(typeof(XmlLanguage));
return (XmlLanguage)ser.Deserialize(doc.CreateReader());
}
I have a class InputConfig which contains a List<IncludeExcludeRule>:
public class InputConfig
{
// The rest of the class omitted
private List<IncludeExcludeRule> includeExcludeRules;
public List<IncludeExcludeRule> IncludeExcludeRules
{
get { return includeExcludeRules; }
set { includeExcludeRules = value; }
}
}
public class IncludeExcludeRule
{
// Other members omitted
private int idx;
private string function;
public int Idx
{
get { return idx; }
set { idx = value; }
}
public string Function
{
get { return function; }
set { function = value; }
}
}
Using ...
FileStream fs = new FileStream(path, FileMode.Create);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(InputConfig));
xmlSerializer.Serialize(fs, this);
fs.Close();
... and ...
StreamReader sr = new StreamReader(path);
XmlSerializer reader = new XmlSerializer(typeof(InputConfig));
InputConfig inputConfig = (InputConfig)reader.Deserialize(sr);
It works like a champ! Easy stuff, except that I need to preserve whitespace in the member function when deserializing. The generated XML file demonstrates that the whitespace was preserved when serializing, but it is lost on deserializing.
<IncludeExcludeRules>
<IncludeExcludeRule>
<Idx>17</Idx>
<Name>LIEN</Name>
<Operation>E =</Operation>
<Function> </Function>
</IncludeExcludeRule>
</IncludeExcludeRules>
The MSDN documentation for XmlAttributeAttribute seems to address this very issue under the header Remarks, yet I don't understand how to put it to use. It provides this example:
// Set this to 'default' or 'preserve'.
[XmlAttribute("space",
Namespace = "http://www.w3.org/XML/1998/namespace")]
public string Space
Huh? Set what to 'default' or 'preserve'? I'm sure I'm close, but this just isn't making sense. I have to think there's just a single line XmlAttribute to insert in the class before the member to preserve whitespace on deserialize.
There are many instances of similar questions here and elsewhere, but they all seem to involve the use of XmlReader and XmlDocument, or mucking about with individual nodes and such. I'd like to avoid that depth.
To preserve all whitespace during XML deserialization, simply create and use an XmlReader:
StreamReader sr = new StreamReader(path);
XmlReader xr = XmlReader.Create(sr);
XmlSerializer reader = new XmlSerializer(typeof(InputConfig));
InputConfig inputConfig = (InputConfig)reader.Deserialize(xr);
Unlike XmlSerializer.Deserialize(XmlReader), XmlSerializer.Deserialize(TextReader) preserves only significant whitespace marked by the xml:space="preserve" attribute.
The cryptic documentation means that you need to specify an additional field with the [XmlAttribute("space", Namespace = "http://www.w3.org/XML/1998/namespace")] whose value is default or preserve. XmlAttribute controls the name of the generated attribute for a field or property. The attribute's value is the field's value.
For example, this class:
public class Group
{
[XmlAttribute (Namespace = "http://www.cpandl.com")]
public string GroupName;
[XmlAttribute(DataType = "base64Binary")]
public Byte [] GroupNumber;
[XmlAttribute(DataType = "date", AttributeName = "CreationDate")]
public DateTime Today;
[XmlAttribute("space", Namespace = "http://www.w3.org/XML/1998/namespace")]
public string Space ="preserve";
}
Will be serialized to:
<?xml version="1.0" encoding="utf-16"?>
<Group xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
d1p1:GroupName=".NET"
GroupNumber="ZDI="
CreationDate="2001-01-10"
xml:space="preserve"
xmlns:d1p1="http://www.cpandl.com" />
I believe the part you are missing is to add the xml:space="preserve" to the field, e.g.:
<Function xml:space="preserve"> </Function>
For more details, here is the relevant section in the XML Specification
With annotation in the class definition, according to the MSDN blog it should be:
[XmlAttribute("space=preserve")]
but I remember it being
[XmlAttribute("xml:space=preserve")]
Michael Liu's answer above worked for me, but with one caveat. I would have commented on his answer, but my "reputation" is not adequate enough.
I found that using XmlReader did not fully fix the issue, and the reason for this is that the .net property in question had the attribute:
XmlText(DataType="normalizedString")
To rectify this I found that adding the additional attribute worked:
[XmlAttribute("xml:space=preserve")]
Obviously, if you have no control over the .net class then you have a problem.
I am writing a set of objects that must serialize to and from Xml, following a strict specification that I cannot change. One element in this specification can contain a mix of strings and elements in-line.
A simple example of this Xml output would be this:
<root>Leading text <tag>tag1</tag> <tag>tag2</tag></root>
Note the whitespace characters between the closing of the first tag, and the start of the second tag. Here are the objects that represents this structure:
[XmlRoot("root")]
public class Root
{
[XmlText(typeof(string))]
[XmlElement("tag", typeof(Tag))]
public List<object> Elements { get; set; }
//this is simply for the sake of example.
//gives us four objects in the elements array
public static Root Create()
{
Root root = new Root();
root.Elements.Add("Leading text ");
root.Elements.Add(new Tag() { Text = "tag1" });
root.Elements.Add(" ");
root.Elements.Add(new Tag() { Text = "tag2" });
return root;
}
public Root()
{
Elements = new List<object>();
}
}
public class Tag
{
[XmlText]
public string Text {get;set;}
}
Calling Root.Create(), and saving to a file using this method looks perfect:
public XDocument SerializeToXml(Root obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
XDocument doc = new XDocument();
using (var writer = doc.CreateWriter())
{
serializer.Serialize(writer, obj);
}
return doc;
}
Serialization looks exactly like the xml structure at the beginning of this post.
Now when I want to serialize an xml file back into a Root object, I call this:
public static Root FromFile(string file)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
XmlReaderSettings settings = new XmlReaderSettings();
XmlReader reader = XmlTextReader.Create(file, settings);
//whitespace gone here
Root root = serializer.Deserialize(reader) as Root;
return root;
}
The problem is here. The whitespace string is eliminated. When I call Root.Create(), there are four objects in the Elements array. One of them is a space. This serializes just fine, but when deserializing, there are only 3 objects in Elements. The whitespace string gets eliminated.
Any ideas on what I'm doing wrong? I've tried using xml:space="preserve", as well as a host of XmlReader, XmlTextReader, etc. variations. Note that when I use a StringBuilder to read the XmlTextReader, the xml contains the spaces as I'd expect. Only when calling Deserialize(stream) do I lose the spaces.
Here's a link to an entire working example. It's LinqPad friendly, just copy/paste: http://pastebin.com/8MkUQviB The example opens two files, one a perfect serialized xml file, the second being a deserialized then reserialized version of the first file. Note you'll have to reference System.Xml.Serialization.
Thanks for reading this novel. I hope someone has some ideas. Thank you!
It looks like a bug. Workaround seems to be replace all whitespaces and crlf in XML text nodes by
entities. Semantic equal entities (
) does not work.
<root>Leading text <tag>tag1</tag> <tag>tag2</tag></root>
is working for me.
I have an XML document format from a legacy system that I have to support in a future application. I want to be able to both serialize and deserialize the XML between XML and C# objects, however, using the objects generated by xsd.exe, the C# serialization includes the xmlns:xsi..., xsi:... etc XML attributes on the root element of the document that gets generated. Is there anyway to disable this so that absolutely no XML attribute nodes get put out in the resulting XML ? The XML document should be elements only.
Duplicate? XmlSerializer: remove unnecessary xsi and xsd namespaces
Yes, use the XmlSerializerNamespaces class.
Example:
var s= new System.Xml.Serialization.XmlSerializer(typeof(TypeToSerialize));
var ns= new System.Xml.Serialization.XmlSerializerNamespaces();
ns.Add( "", "");
System.IO.StreamWriter writer= System.IO.File.CreateText(filePath);
s.Serialize(writer, objectToSerialize, ns);
writer.Close();
See also: XmlSerializer: remove unnecessary xsi and xsd namespaces
There is no way to force XML Serializer to ignore xsi attributes (unless you implement IXmlSerializable and force custom serialization or use XmlAttributeOverrides). However the only time xsi: attributes show up is when you have a nullable element. If you do need to use nullable elements you can of course post-process the XML to remove all xsi: occurences. However if you do this think about how you will deserialize the XML back into an object, if xsi:nil is missing on an element and the element is defined as a nullable integer you will run into an exception.
#Cheeso, please correct me if i am wrong.
I have the following code.
public class TestSer
{
public int? MyProperty { get; set; }
}
TestSer ser = new TestSer();
ser.MyProperty = null;
StringBuilder bldr = new StringBuilder();
var ns = new System.Xml.Serialization.XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer s = new XmlSerializer(typeof(TestSer));
using (StringWriter writer = new StringWriter(bldr))
{
s.Serialize(writer, ser, ns);
}
I get the following output.
<?xml version="1.0" encoding="utf-16"?>
<TestSer>
<MyProperty d2p1:nil="true" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance" />
</TestSer>
This isn't exactly element only as the question asks for.