I have two classes which need to be in same xml file. The way the classes are done mean I'm having to serialize separately. Which I have managed to do. The first I do using TextWriter.
TextWriter writer = new StreamWriter(filepath);
serializer.Serialize(writer, class, ns);
This works fine. Then I wanted to add another class to the file. So did same but added that I want to append not overwrite.
TextWriter writer = new StreamWriter(filepath, true);
This adds the new class to end but also adds another declaration so my XML file reads.
<?xml version="1.0" encoding"utf-8"?>
<dog>
...
</dog>
<?xml version="1.0" encoding"utf-8"?>
<cat>
...
</cat>
I've tried to use XmlWriter so I could use XmlWriterSettings then chose false for OmitXmlDeclaration but then it overrides the previous class I serialized.
Your XML needs a root element to be valid XML.
<?xml version="1.0" encoding"utf-8"?>
<animals>
<dog/>
<cat/>
<animals>
You could create a List<Animal> and serialize it. But if you do not have the same superclass, you can try to create a class like this:
[Serializable]
public class AnimalCollection : IXmlSerializable
{
public void WriteXml(XmlWriter writer)
{
// Repeat for the Cat
writer.WriteStartElement("Dog");
XmlSerializer serializer = new XmlSerializer(TypeOf(Dog));
using (StringWriter stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, _dog);
string value = stringWriter.ToString();
writer.WriteRaw(value);
}
writer.WriteEndElement();
}
}
in the ReadXml and WriteXml you could use the generic serializer to serialize those objects then use the XmlWriter to write a startElement. endElement and include the serialized animal.
What you want to do is not valid XML, as it can only contain a single root element.
You could create a class to contain dog and cat, and serialize that.
Related
I'm currently working with generating XML files used to configure a server.
I've got a class generated with xsd which contains a property of the type System.Xml.XmlElement.
public class GeneratedClass
{
...
private System.Xml.XmlElement informationField;
[System.Xml.Serialization.XmlArrayItemAttribute("Information", IsNullable=false)]
public System.Xml.XmlElement Information {
get {
return this.informationField;
}
set {
this.informationField = value;
}
}
...
}
I'm having troubles "injecting" a custom object into this Information property.
public class MyExampleObject
{
public string Name { get; set; }
public string Id { get; set;
}
The program deserializes a xml file of the type GeneratedClass and after this I want to add MyExampleObject to the Informations property.
The way I currently do this is with this method:
XmlDocument doc = new XmlDocument();
using (XmlWriter writer = doc.CreateNavigator().AppendChild())
{
XmlSerializer serializer = new XmlSerializer(typeof(MyExampleObject));
serializer.Serialize(writer, MyObject);
}
this.Information = doc.DocumentElement;
After this I serialize the whole object to file, but when I do this I get unwanted xml namespace attributes.
<Information xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="">
I've found other posts with similar problems, but the suggested solutions, leaves me with <Information xmlns=""> which is still not a complete solution.
I get the feeling that there might be some other way to do this, but I'm not sure how.
Any suggestions?
I know that this post is very old :) But perhaps might come in handy for others seeking answer to this
Update Sorry I was a bit quick reading your question and focus on my own problem which was also regarding namespaces in some sense, but more how to remove one. I see that you use XmlSerializer and unfortunately I don't know how to manipulate namespaces added as attribute on class to serialize. Perhaps look at XmlRootAttribute that you can pass to XmlSerializer.ctor and then you have XmlSerializerNamespaces which is passed during serialization and provide mean to manipulate namespaces.
I recently stumbled upon this as well and found a solution.
var xmlDocument = new XmlDocument();
var xmlElement = xmlDocument.CreateElement(Prefix, "Document", Ns);
xmlElement.InnerXml = string.Empty;
var navigator = xmlElement.CreateNavigator();
navigator.AppendChildElement(Prefix, "InfRspnSD1", Ns, null);
navigator.MoveToFirstChild();
navigator.AppendChildElement(Prefix, "InvstgtnId", Ns, "123456789");
// At this point xmlElement contains XML and can be assigned
// to the generated class
// For pretty print only
using var sw = new StringWriter();
using var writer = System.Xml.XmlWriter.Create(sw, Settings);
xmlElement.WriteTo(writer);
writer.Flush();
return sw.ToString();
(Code on GitHub)
What I've noticed is that the namespace is included twice, one in the root node and then once again immediate descendant (first child).
# Generate XML using XNavigator
<?xml version="1.0" encoding="utf-16"?>
<supl:Document xmlns:supl="urn:iso:std:iso:20022:tech:xsd:supl.027.001.01">
<supl:InfRspnSD1 xmlns:supl="urn:iso:std:iso:20022:tech:xsd:supl.027.001.01">
<supl:InvstgtnId>123456789</supl:InvstgtnId>
</supl:InfRspnSD1>
</supl:Document>
--------------------
I need to create a file in XML using XmlWriter including for each tag the namespace\schema.
First I have a class produced by xsd schema file, I create the class with all objects and finally I serialize the class writing xml:
myclass root = new myclass();
root.val1 = "temp1";
root.val2 = "temp2";
[...]
using (XmlWriter writer = XmlWriter.Create(Path.Combine("myfile.xml"), s))
{
serializer.Serialize(writer, root);
the problem is that it creates the tags like that:
<Message>
<val1> temp1 </val1>
<val2> temp2 </val2>
<Message>
I want to write the tags as:
<temp:Message>
<temp:val1> temp1 </val1>
<temp:val2> temp2 </val2>
<temp:Message>
can I use some attribute in my class to add temp: starting tags?
I need also to add to my root tag some namespace:
<temp:Message
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="myxml.xsd"
xmlns:stf="urn:oecd:ties:stf:v4"
xmlns:mesage="urn:oecd:ties:cbc:v1"
xmlns:iso="urn:oecd:ties:isocbctypes:v1"
version="1.0">
so I need to add to root class:
1) xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2) xsi:schemaLocation="myxml.xsd"
3) xmlns:mesage="urn:oecd:ties:cbc:v1"
4) etc...
how can I do that?
you can attache temp by doing as below , attach namespace with you xml
var xsn = new XmlSerializerNamespaces();
xsn.Add("temp", "http://namespaceforxml");
XmlSerializer s = new XmlSerializer(typeof(Message));
Message msg = new Message();
// Writing a file requires a TextWriter.
TextWriter t = new StreamWriter(filename);
s.Serialize(t,msg,ns);
t.Close();
decorate calss as below
[XmlRoot(ElementName = "Message", Namespace = "//namespaceforxml")]
public class Message
{
[XmlElement(ElementName = "val1")]
public string val1{ get; set; }
}
I have used XDocument to create simple xml document.I have created document with XDocument and XDeclaration.
XDocument encodedDoc8 = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Root", "Content"));
If i save this document to file means the encoding type is not changed.
using (TextWriter sw = new StreamWriter(#"C:\sample.txt", false)){
encodedDoc8.Save(sw);
}
Output:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Root>Content</Root>
But,if I use XDocument's WriteTo method to print the xml means encoding type is changed.
using (XmlWriter writ = XmlWriter.Create(Console.Out))
{
encodedDoc8.WriteTo(writ);
}
Output:
<?xml version="1.0" encoding="IBM437" standalone="yes"?><Root>Content</Root>
Why this happened?.Please update your answers.Thanks in advance.
If you look at the reference source for XmlWriter.Create, the chain of calls would eventually lead to this constructor:
public XmlTextWriter(TextWriter w) : this() {
textWriter = w;
encoding = w.Encoding;
xmlEncoder = new XmlTextEncoder(w);
xmlEncoder.QuoteChar = this.quoteChar;
}
The assignment encoding = w.Encoding provides an explanation to what is happening in your case: the Encoding setting of the Console.Out text writer is copied to the encoding setting of the newly created XmlTextWriter, replacing the encoding that you supplied in the XDocument.
I'm building an Parts app in order to learn C# and WPF. I trying having trouble adding new parts using XmlWriter. I can create the xml file, but can not figure how to add additional parts. Should I be using something else like XmlDocument? Here is my code behind:
private void btnSave_Click(object sender, RoutedEventArgs e)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create("f:\\MyParts.xml", settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("MyParts");
writer.WriteStartElement("parts");
writer.WriteStartElement("item");
writer.WriteString(txtbxitem.Text);
writer.WriteEndElement();
writer.WriteStartElement("color");
writer.WriteString(txtbxcolor.Text);
writer.WriteEndElement();
writer.WriteStartElement("size");
writer.WriteString(txtbxsize.Text);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
writer.Close();
}
}
This code creates the xml file and a node correctly, but how do I add additional parts? Here is what I am trying to create:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<MyParts>
<parts>
<item>Part1</item>
<color>Red</color>
<size>SM</size>
</parts>
<parts>
<item>Part2</item>
<color>Blue</color>
<size>XXL</size>
</parts>
</MyParts>
Personally I'd suggest using LINQ to XML. It's a much easier API to use than XmlDocument.
But yes, if you want to modify an existing document then typically using an in-memory representation is simpler than using a streaming API. It's possible to do the latter of course, but it's not easy.
Here's an example to create the same XML as you've already got (other than the declaration: any reason you'd want to use Latin-1 instead of something like UTF-8 which can represent the whole of Unicode, btw?)
var doc = new XDocument(
new XElement("MyParts",
new XElement("parts",
new XElement("item", "Part1"),
new XElement("color", "Red"),
new XElement("size", "SM")),
new XElement("parts",
new XElement("item", "Part2"),
new XElement("color", "Blue"),
new XElement("size", "XXL"))));
Then if you wanted to add another part:
doc.Root.Add(
new XElement("parts",
new XElement("item", "Part3"),
new XElement("color", "Green"),
new XElement("size", "L")));
Admittedly I'd expect you'd want to encapsulate the "create a parts element" bit into a method to avoid repeating it all the time... but hopefully you get the picture.
Use a loop, and you'll end up with something like:
var parts = new List<Part>() { ...... parts here ...... };
using (XmlWriter writer = XmlWriter.Create("f:\\MyParts.xml", settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("MyParts");
foreach(var part in parts)
{
writer.WriteStartElement("parts");
writer.WriteStartElement("item");
writer.WriteString(part.Item);
writer.WriteEndElement(); // </item>
writer.WriteStartElement("color");
writer.WriteString(part.Color);
writer.WriteEndElement();
writer.WriteStartElement("size");
writer.WriteString(part.Size);
writer.WriteEndElement(); // </size>
writer.WriteEndElement(); // </parts>
}
writer.WriteEndElement(); // </MyParts>
writer.WriteEndDocument();
writer.Flush();
writer.Close();
}
The general idea is that, for each part in your list of parts, you write the "parts" (should be "part"?) tag and all of its contents, filling item, color and size with data from a Part class, which in its simplest form might be:
class Part
{
public string Item { get; set; }
public Color Color { get; set; }
public string Size { get; set; }
}
The code above does exactly what it looks like: writes an element "MyParts" and then writes a child element "parts" and then a child element "item" with a value of whatever is in your text box.
This smells suspiciously like homework, and is readily Google-able, so I'm only going to give a quick pseudo-answer.
You (may) want to:
Create appropriate class(es) for parts that have the members you want
Create a collection of those items
Update that in-memory collection from your UI
Save the collection using the XML formatting and functionality of your choice (including but not limited to what you are doing above, or LINQ to XML, or XML Serialization, or...)
Have you considered using the out of the box XML Serialization that comes with .NET? You just populate your objects within some collection and then use the XML Serializer to persist to a file. You can then use the DeSerializer to hydrate your objects.
This would allow your to spend more time on your application's UI (WPF), and logic. All you need to do is all the Serializable attribute to your class.
Here's a good example: http://www.jonasjohn.de/snippets/csharp/xmlserializer-example.htm
The biggest benefit is that as you build your data object over time, the serialization/de-serialization will grow with it.
I am serializing an object in my ASP.net MVC program to an xml string like this;
StringWriter sw = new StringWriter();
XmlSerializer s = new XmlSerializer(typeof(mytype));
s.Serialize(sw, myData);
Now this give me this as the first 2 lines;
<?xml version="1.0" encoding="utf-16"?>
<GetCustomerName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
my question is,
How can I change the xmlns and the encoding type, when serializing?
Thanks
What I found that works was to add this line to my class,
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://myurl.com/api/v1.0", IsNullable = true)]
and add this to my code to add namespace when I call serialize
XmlSerializerNamespaces ns1 = new XmlSerializerNamespaces();
ns1.Add("", "http://myurl.com/api/v1.0");
xs.Serialize(xmlTextWriter, FormData, ns1);
as long as both namespaces match it works well.
The XmlSerializer type has a second parameter in its constructor which is the default xml namespace - the "xmlns:" namespace:
XmlSerializer s = new XmlSerializer(typeof(mytype), "http://yourdefault.com/");
To set the encoding, I'd suggest you use a XmlTextWriter instead of a straight StringWriter and create it something like this:
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
XmlTextWriter xtw = XmlWriter.Create(filename, settings);
s.Serialize(xtw, myData);
In the XmlWriterSettings, you can define a plethora of options - including the encoding.
Take a look at the attributes that control XML serialization in .NET.
Specifically, the XmlTypeAttribute may be useful for you. If you're looking to change the default namespace for you XML file, there is a second parameter to the XmlSerializer constructor where you can define that.