My XmlSerializer code is outputting Xml that is much more verbose than I require, how can I control the output settings properly? This is the code:
var stream = new MemoryStream();
var xmlSerializer = new XmlSerializer(objectToSerialize.GetType());
xmlSerializer.Serialize(stream, objectToSerialize);
string xml = encoding != null ? encoding.GetString(stream.ToArray())
: Encoding.Default.GetString(stream.ToArray());
And the output looks like this:
<?xml version="1.0"?>
<ArrayOfProduct xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Product>
<Id>1</Id>
<ProductCode>A</ProductCode>
<ProductDescription>Product A</ProductDescription>
<Obsolete xsi:nil="true"></Obsolete>
</Product>
</ArrayOfProduct>
I want to be able to format the Xml like so:
Remove the xsi:nil="true" from lines with no value
Collapse empty tags like <Obsolete></Obsolete> into the simple form <Obsolete />
When you decorate the class and members using [Serializable] the objects are serialized using the old methods which does not contains xsi:nil="true
But when you decorate the class with [DataContract] attribute the XmlSerializer will include the xsi:nil="true.
One way to remove xsi:nil="true is to
decorate the class with [Serializable] attribute.
Related
I've got an xml-file that looks like this for example:
<?xml version="1.0" encoding="UTF-8"?>
<Adresses>
<Message>
<Header>
<MessageID>96</MessageID>
<Timestamp>22.08.2014 10:25:01</Timestamp>
</Header>
<Body>
<Person SurName="Muster" Prename="Max">
<Adress Street="Street 1"/>
</Person>
<Person SurName="Muster" Prename="Max">
<Adress Street="Street 1"/>
</Person>
<Person SurName="Muster" Prename="Max">
<Adress Street="Street 1"/>
</Person>
</Body>
</Message>
</Adresses>
From this xml I only want the part inside the body-tags. I do the deserialization with the XmlSerializer and annotaions. So I have models that look like this
[XmlRoot("Body")]
public class BodyXml
{
public BodyXml()
{}
[XmlElement("Person")]
public Person[] Persons { get; set; }
}
Now my question is how can I get the XmlSerializer to serialize from the body-tag and not from the adresses-tag? Do I need another annotation somewhere in my models?
thanks and greets
Depending on other constraints, either consider writing a quick and dirty wrapper that would deserialize the whole XML (with BodyXml as it's member), or alternatively select only the relevant part of your xml, e.g.:
var serializer = new XmlSerializer(typeof(BodyXml));
var xDoc = XDocument.Parse(YOUR_XML_STRING);
using (var xmlReader = xDoc.Descendants("Body").Single().CreateReader())
{
var result = serializer.Deserialize(xmlReader);
}
EDIT: without any context I'd go with the latter.
use XmlIgnoreAttribute
You can Add Address property as below
[XmlIgnoreAttribute]
public AddressClass Adress{get;set;}
Here AddressClass may type of your Address property or some other class.
I am playing around with this simple tutorial in C# and here is the kind of XML you can GET.
<Person xmlns="http://schemas.datacontract.org/2004/07/RESTfulDemo"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Age>23</Age>
<ID>1</ID>
<Name>Bob Kohler</Name>
</Person>
Here is the Person.cs class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
namespace RESTfulDemo
{
[DataContract]
public class Person
{
[DataMember]
public string ID;
[DataMember]
public string Name;
[DataMember]
public string Age;
}
}
1) How should can I add attributes / Prefixes in my XML for each data member ?
2) How can I set the heading of my XML to this (or anything else) :
<?xml version="1.0"?>
question 2) can be done when initializing a document:
XDocument document = new XDocument(new XDeclaration("1.0", "utf-16", "yes"));
as for question 1), from what I have understood, if you have such XML file:
<CATALOG>
<CD>
<TITLE> ... </TITLE>
<ARTIST> ... </ARTIST>
<YEAR> ... </YEAR>
</CD>
</CATALOG>
and you need to add an attribute "id" for the CD node,
(where the id is automatically incremented)
XmlNodeList list = document.GetElementsByTagName("CATALOG");
int i = 0;
foreach (XmlNode CD in list)
{
i++;
XmlAttribute idAttr = document.CreateAttribute("id");
idAttr.Value = i.ToString();
CD.Attributes.Append(idAttr); //to append the created attribute and its value to the CD node
}
So, here is what I did to overcome this problem. The solution does not involve Serialization but at least it enables to format the response like you want.
(1) Put XElement from System.xml.linq as return type of each method and build the xml with the XElement class in each method.
(2) Use exactly the code provided here to add the xml declaration on top of your xml response. Thanks to #Dash for the link.
I have a DataSet with data that I output (write) to an XMl file.
I have added a namespace and prefix to the dataset like this:
public static string XmlNamespace = "http://namespace";
public static string XmlPrefix = "ns0";
RequestDataSet.Namespace = XmlNamespace;
RequestDataSet.Prefix = XmlPrefix;
The XML output is as follows:
<?xml version="1.0" standalone="yes"?>
<ns0:list xmlns:ns0="http://namespace">
<ns0:item xmlns="http://namespace">
<data1>1234</data1>
<data2>91011</data2>
</item>
</ns0:list>
But it should be like this: (no namespace on the item records. Just the prefix)
<?xml version="1.0" standalone="yes"?>
<ns0:list xmlns:ns0="http://namespace">
<ns0:item>
<data1>1234</data1>
<data2>91011</data2>
</item>
</ns0:list>
I have tried setting the tables prefix/namespace to null like this:
RequestDataSet.Tables["item"].Prefix = XmlPrefix;
RequestDataSet.Tables["item"].Namespace = null;
But that also does not work... Does anyone know a solution for this?
I've come across similar issues when fighting with BizTalk adapters... but that's a different story.
Not sure if there is a different (cleaner) way, but you could always 'grab' the attribute and remove it, as decribed here.
Effectively you would do the following:
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(xml);
if (xDoc.DocumentElement.Attributes.Count > 0)
{
XmlAttribute xAtt = xDoc.DocumentElement.Attributes[0];
xDoc.DocumentElement.Attributes.Remove(xAtt);
I have the following XML structure
<T>
<F>
<H>
<H1>some value</H1>
<H2>some value</H2>
<H3>some value</H3>
</H>
<O>
<P>some value</P>
<TI>some value</TI>
<TI>some value</TI>
</O>
<R>
<PTY>some value</PTY>
<PTY>some value</PTY>
<PTY>some value</PTY>
</R>
</F>
<T>
I need to parse this xml in C# and get the values out of them to be further exported to a CSV file.
My query is how do you go about creating an entity for this XML
You can play with XmlSerializer and its related attributes.
As long as the XML is not too complex, there's not much work to do.
To read the XML:
var serializer = new XmlSerializer(typeof(SerializableObject));
SerializableObject deserialized;
using (var stream = new FileStream(#"C:\test.xml", FileMode.Open))
{
deserialized = (SerializableObject)serializer.Deserialize(stream);
}
The SerializableObject will look like this:
[Serializable]
[XmlRootAttribute("T")]
public class SerializableObject
{
...
}
BONUS for lazy programmers: You can just use Xsd.exe to brute force create an object from an XML file. Then tweak the results to your needs.
You can use LinqToXml to parse xml. StringBuilder will be helpful to produce CSV.
I think these How Tos will be useful. They describe all you needed to parse this xml.
add using System.Xml.Linq;
then you can do something similar to this:
XDocument xml = XDocument.Load(#"....\People.xml");
var query = from p in xml.Elements("people").Elements("person")
where (int)p.Element("id") == 1
select p;
I'm trying to deserialize the following XML output:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Foo>
<Val>Data1</Val>
</Foo>
<Foo>
<Val>Data2</Val>
</Foo>
(This is output from a hardware device, and cannot be changed)
I have an XML type defined as:
[XmlType(AnonymousType=true, Namespace="")]
public class Foo
{
public string Val { get; set; }
}
I've tried to deserialize this array by creating a serializer like:
var s = new XmlSerializer(typeof(Foo[]));
//or
var s = new XmlSerializer(typeof(List<Foo>);
But every call to s.Deserialize() causes an InvalidOperaitonException:
System.InvalidOperationException: <Foo xmlns=''> was not expected.
Note
var s = new XmlSerializer(typeof(Foo));
// Only deseralizes the first Foo (Data1).
Thanks for your help.
I think the issue is with your provided xml.
Test app says
List<Foo> list = new List<Foo> {new Foo {Val = "Data1"}, new Foo {Val = "Data2"}};
var s = new XmlSerializer(typeof(List<Foo>));
StringBuilder sb = new StringBuilder();
XmlWriter wr = XmlWriter.Create(sb);
s.Serialize(wr, list);
string ss = sb.ToString();
var s2 = new XmlSerializer(typeof(List<Foo>));
StringReader sr = new StringReader(ss);
List<Foo> returnList = (List<Foo>)s2.Deserialize(sr);
And the XML should be
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfFoo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Foo>
<Val>Data1</Val>
</Foo>
<Foo>
<Val>Data2</Val>
</Foo>
</ArrayOfFoo>
If you can remove the inital line
<?xml version="1.0" encoding="ISO-8859-1"?>
And minipulate the string into
string s = "<ArrayOfFoo><Foo> <Val>Data1</Val></Foo><Foo> <Val>Data2</Val></Foo></ArrayOfFoo>";
var s2 = new XmlSerializer(typeof(List<Foo>));
StringReader sr = new StringReader(s);
List<Foo> list = (List<Foo>)s2.Deserialize(sr);
That could work.
That isn't valid Xml. There needs to be a core root element for it to work properly.
this is not a valid xml so you can not deserialize it like a valid xml. You need some kind of hack to make this work. i'd suggest to insert at beginning of the xml and inserting at the end of xml. then you can deserialize it, since you cant make this change at xml side, do it in your code.
String ss;
// lets assume this holds your xml data in string.
ss.append("</ArrayOfFoo>");
ss.replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", "<?xml version=\"1.0\" encoding=\"utf-16\"?> <ArrayOfFoo>")
var s2 = new XmlSerializer(typeof(List<Foo>));
StringReader sr = new StringReader(ss);
List<Foo> returnList = (List<Foo>)s2.Deserialize(sr);
now this shall return you the correct list.
As the other posters say, this XML that the hardware device produces is not compatible to the way .NET serializes/deserializes object. Valid XML, and .NET requires valid XML, has a root element.
I suggest:
either you modify your obtained XML to match the way astander presents in his xml code snippet.
or you write a simple xml parser for your file that deserializes the file like you need
br, Marcel
Technically, what you have there is not a well-formed XML document (which has exactly one root element), but rather an well-formed external parsed entity (which can have any number of elements not contained in other elements, as well as text not contained in any elements). Therefore, it should parse if your XML parser has an entry point for parsing EPEs rather than documents. You could also create a stub document which includes by reference your EPE and parse that document.
Xstream for .Net could be a useful API