Remove xmlns:i and xmlns from webapi - c#

I have been asked to provide the following XML document from an http endpoint, exactly like:-
<?xml version="1.0" encoding="utf-8"?>
<XMLFile xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SalesOrders>
...
</SalesOrders>
However Web API spits out
<?xml version="1.0" encoding="utf-8"?>
<XMLFile xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/White.Label.Ordering.Infrastructure.Data.Queries.Export">
<SalesOrders>
...
</SalesOrders>
I have google around and tried various fixes but to no avail, my model looks like
[DataContract]
public class XMLFile
{
[DataMember]
public List<SalesOrder> SalesOrders { get; set; }
}
[DataContract]
public class SalesOrder
{
[DataMember(Order = 1)]
public string OrderNumber { get; set; }
}
and my set up lools like this
public static void Register(HttpConfiguration config)
{
config.Formatters.XmlFormatter.WriterSettings.OmitXmlDeclaration = false;
...
}
How do I remove xmlns:i and xmlns and replace with xmlns:xsd and xmlns:xsi?
I know this is a bad question as it shouldn't matter but my consuming client is barfing.

If you need your XML to look exactly like something, then you might be better off with XmlSerializer. DataContractSerializer doesn't give you the same level of control as it's rather assumed you use it on both ends.
That said, I would imagine your consuming client is 'barfing' because the two instances are semantically different. The first has an empty default namespace, and the second has a default namespace of http://schemas.datacontract.org/2004/07/White.Label.Ordering.Infrastructure.Data.Queries.Export.
This should be the only thing you need to correct, which you can do by setting the namespace of the DataContract.
[DataContract(Namespace="")]
public class XMLFile
{
[DataMember]
public List<SalesOrder> SalesOrders { get; set; }
}
[DataContract(Namespace="")]
public class SalesOrder
{
[DataMember(Order = 1)]
public string OrderNumber { get; set; }
}
This will give you:
<?xml version="1.0" encoding="utf-8"?>
<XMLFile xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<SalesOrders>
...
</SalesOrders>
</XMLFile>

Related

c# serialize object without root element

I am working with a 3rd party who has an xml structure for multiple different requests.
Each request has a common header structure and then some specific footer data.
Unfortunately, the header and footer sections are not wrapped within their own element tags and this is something that I can't change.
Some sample contrived requests are shown below:
Sample Request 1
<?xml version="1.0" encoding="UTF - 8" standalone="yes"?>
<Request>
<RequestType>1</RequestType>
<User>User01</User>
<id>1234</id>
<Name>John</Name>
<Age>20</Age>
</Request>
Sample Request 2
<?xml version="1.0" encoding="UTF - 8" standalone="yes"?>
<Request>
<RequestType>2</RequestType>
<User>User02</User>
<id>1235</id>
<School>The School</School>
<Teacher>Mrs Smith</Teacher>
</Request>
Sample Request 3
<?xml version="1.0" encoding="UTF - 8" standalone="yes"?>
<Request>
<RequestType>3</RequestType>
<User>User01</User>
<id>223</id>
<Work>The Office</Word>
<Boss>Mr White</Boss>
<Phone>1234567</Phone>
<Payday>Friday</Payday>
</Request>
You can see that each request has a RequestType, User and id.
My question relates to writing C# code that will encapsulate this Xml for serialization.
To me, it seems wrong to have each of my C# classes having the repeated header (RequestType, User and id) data.
I have tried using generics (see sample code below) but that leads to my question.
Question: How can I serialize my generic object Footer so that it is not wrapped within "root" Footer element?
[System.Xml.Serialization.XmlRoot("Request")]
public class GenericRequest<typeT>
{
public GenericRequest()
{
}
public int RequestType { get; set; }
public string User { get; set; }
public int id { get; set; }
public typeT Footer { get; set; }
}
You can create a class with interface IFooter, which can have different implementor as per requirement (e.g.
interface IFooter : ISerializable
{
//Define common member.
}
public class Footer1: IFooter
{
// define members (e.g. work)
}
public class Footer2: IFooter
{
// define members
}
public class Footer3: IFooter
{
// define members
}
Now serialize main class
[System.Xml.Serialization.XmlRoot("Request")]
public class GenericRequest
{
public GenericRequest()
{
}
public int RequestType { get; set; }
public string User { get; set; }
public int id { get; set; }
public IFooter Footer { get; set; }
}
Visit How can I serialize an object that has an interface as a property? for reference.

Class not serializing as expected

I've been struggling with this all day. I done a lot of research, but I just can't seem to put it all together.
I have a XML response from a server like so:
<?xml version="1.0" ?>
<inboxRecords>
<inboxRecord>
<field1 />
<field2 />
<field3 />
</inboxRecord>
<inboxRecord>
<field1 />
<field2 />
<field3 />
</inboxRecord>
</inboxRecords>
I created the following code to represent the response. The intention is that I will de-serialize the response using the following:
[XmlRoot("inboxRecords")]
public sealed class QueueQueryResult
{
public InboxRecord[] InboxRecords;
public QueueQueryResult()
{
InboxRecords = null;
}
public sealed class InboxRecord
{
public string field1 { get; set; }
public string field2 { get; set; }
public string field3 { get; set; }
}
}
The classes above are based on one of the numerous examples I found online. The problem is, when I serialize the class above (to confirm that it is correct), it comes out like this:
<?xml version="1.0" encoding="utf-16"?>
<inboxRecords>
<InboxRecords>
<InboxRecord>
<field1>some value</field1>
</InboxRecord>
<InboxRecord>
<field1>some value</field1>
</InboxRecord>
</InboxRecords>
</inboxRecords>
So, first problem, how do I get rid of the extra InboxRecords element? I only want the root to say that (with a small 'i'). Second, for quick testing, I only put a value in the first field. Why didn't the other fields come out as empty elements? Do I need another decorator for that?
Thanks!
Thanks!
Use the XmlElement attribute:
[XmlRoot("inboxRecords")]
public sealed class QueueQueryResult
{
[XmlElement("inboxRecord")]
public InboxRecord[] InboxRecords;
public QueueQueryResult()
{
InboxRecords = null;
}
public sealed class InboxRecord
{
public string field1 { get; set; }
public string field2 { get; set; }
public string field3 { get; set; }
}
}
This removes the Array wrapper element and allows you to control the name for each xml element so that you can use lower case names.
Untested, but I reckon you could probably do something like this:
[XmlRoot("inboxRecords")]
public sealed class QueueQueryResult : Collection<QueueQueryResult.InboxRecord>
{
public QueueQueryResult()
{
InboxRecords = null;
}
public sealed class InboxRecord
{
public string field1 { get; set; }
public string field2 { get; set; }
public string field3 { get; set; }
}
}
The problem with your code is that you've got a member InboxRecords within an object that is serialising to inboxRecords. By making the class inherit from Collection, you're providing it with the capability to handle a set of InboxRecords without the extra inner element.
After generating an XSD from your first sample XML (and then a .cs) using xsd.exe, I can create and serialize an instance from your second example:
<?xml version="1.0" encoding="utf-16"?>
<inboxRecords xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<inboxRecord>
<field1>some value</field1>
</inboxRecord>
<inboxRecord>
<field1>some value</field1>
</inboxRecord>
</inboxRecords>
With the exception of the encoding attribute and the schema namespace, this looks pretty darn similar to the first sample.

Deserialize XML to object (need to return a list of objects)

Started practicing with XML and C# and I have an error message of "There is an error in XML document (3,2)". After looking at the file, I can't see anything wrong with it (Mind you, I probably missed something since I'm a noob). I'm using a Console Application for C# right now. I'm trying to return a list of Adventurers and just a side note, the GEAR element is optional. Here is what I have so far:
XML File - Test1
<?xml version="1.0" encoding="utf-8"?>
<Catalog>
<Adventurer>
<ID>001</ID>
<Name>John Smith</Name>
<Address>123 Fake Street</Address>
<Phone>123-456-7890</Phone>
<Gear>
<Attack>
<Item>
<IName>Sword</IName>
<IPrice>15.00</IPrice>
</Item>
<Item>
<IName>Wand</IName>
<IPrice>20.00</IPrice>
</Item>
</Attack>
<Defense>
<Item>
<IName>Shield</IName>
<IPrice>5.00</IPrice>
</Item>
</Defense>
</Gear>
</Adventurer>
<Adventurer>
<ID>002</ID>
<Name>Guy noone likes</Name>
<Address>Some Big House</Address>
<Phone>666-666-6666</Phone>
<Gear></Gear>
</Adventurer>
</Catalog>
C# Classes
public class Catalog
{
List<Adventurer> Adventurers { get; set; }
}
public class Adventurer
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public Gear Gear { get; set; }
}
public class Gear
{
public List<Item> Attack { get; set; }
public List<Item> Defense { get; set; }
}
public class Item
{
public string IName { get; set; }
public decimal IPrice { get; set; }
}
Serialize Function - Where the Problem Occurs at Line 5
Catalog obj = null;
string path = #"C:\Users\Blah\Desktop\test1.xml";
XmlSerializer serializer = new XmlSerializer(typeof(Catalog));
StreamReader reader = new StreamReader(path);
obj = (Catalog)serializer.Deserialize(reader);
reader.Close();
Console.ReadLine();
The issue is the list of Adventurers in Catalog:
<?xml version="1.0" encoding="utf-8"?>
<Catalog>
<Adventurers> <!-- you're missing this -->
<Adventurer>
</Adventurer>
...
<Adventurer>
</Adventurer>
</Adventurers> <!-- and missing this -->
</Catalog>
You don't have the wrapping element for the Adventurers collection.
EDIT: By the way, I find the easiest way to build the XML structure and make sure it's compatible is to create the object(s) in C#, then run through the built-in XmlSerializer and use its XML output as a basis for any XML I create rather than forming it by hand.
First, "Adventurers" property is not public, it's inaccessible, I think that the best way to find the error is to serialize your object and then compare the result with your xml file.
Your XML doesn't quite line up with your objects... namely these two...
public string City { get; set; }
and
<Address>123 Fake Street</Address>
Change City to Address or vice versa and it should fix the problem.
Edit: Got this to work in a test project, combination of all our answers...
Add <Adventurers> tag after <Catalog> (and </Adventurers> before </Catalog>) and change
List<Adventurer> Adventurers { get; set; }
to
public List<Adventurer> Adventurers { get; set; }
and it works properly for me.
I was able to get your xml to deserialize with a couple minor changes (namely the public qualifier on Adventurer).
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
namespace TempSandbox
{
[XmlRoot]
public class Catalog
{
[XmlElement("Adventurer")]
public List<Adventurer> Adventurers;
private readonly static Type[] myTypes = new Type[] { typeof(Adventurer), typeof(Gear), typeof(Item) };
private readonly static XmlSerializer mySerializer = new XmlSerializer(typeof(Catalog), myTypes);
public static Catalog Deserialize(string xml)
{
return (Catalog)Utils.Deserialize(mySerializer, xml, Encoding.UTF8);
}
}
[XmlRoot]
public class Adventurer
{
public int ID;
public string Name;
public string Address;
public string Phone;
[XmlElement(IsNullable = true)]
public Gear Gear;
}
[XmlRoot]
public class Gear
{
public List<Item> Attack;
public List<Item> Defense;
}
[XmlRoot]
public class Item
{
public string IName;
public decimal IPrice;
}
}
I'm using [XmlElement("Adventurer")] because the xml element names don't exactly match the class property names.
NOTE: I'm using a generic deserialization utility i already had on hand .

Recursive XML Deserialization

I have some XML that I am trying to deserialize the xml below.
<?xml version="1.0" encoding="UTF-8"?>
<disproot version="1.0">
<header>
<msg-type> init_req </msg-type>
<txn-id> 0090 </txn-id>
</header>
<body />
</disproot>
My object is something like this.
[XmlRoot("disproot")]
public class Request
{
[XmlAttribute("version")]
public string Version
{ get; set; }
[XmlElement("header", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
Header header = new Header();
}
public class Header
{
public Header()
{
}
[XmlElement("txn-id")]
public string TransactionId
{
get;
set;
}
[XmlElement("msg-type")]
public string MessageType
{
get;
set;
}
}
My Header's object is not populated. The members are displaying as Null values. See below.
Request.Header.TasnsactionId's value is Null
Request.Header.MessageType's value is also Null
Anything wrong I am doing here?
Any help would be appreciable.
XML serialization works only on public members. So, you can change the field to
public Header header = new Header();
and it should work fine. Although I would advise you against using public fields, you should probably make it into a property:
public Header Header { get; set; }

Problem with Serialization/Deserialization an XML containing CDATA attribute

I need to deserialize/serialize the xml file below:
<items att1="val">
<item att1="image1.jpg">
<![CDATA[<strong>Image 1</strong>]]>
</item>
<item att1="image2.jpg">
<![CDATA[<strong>Image 2</strong>]]>
</item>
</items>
my C# classes:
[Serializable]
[XmlRoot("items")]
public class RootClass
{
[XmlAttribute("att1")]
public string Att1 {set; get;}
[XmlElement("item")]
public Item[] ArrayOfItem {get; set;}
}
[Serializable]
public class Item
{
[XmlAttribute("att1")]
public string Att1 { get; set; }
[XmlText]
public string Content { get; set; }
}
and everything works almost perfect but after deserialization in place
<![CDATA[<strong>Image 1</strong>]]>
I have
<strong>Image 1</strong>
I was trying to use XmlCDataSection as type for Content property but this type is not allowed with XmlText attribute. Unfortunately I can't change XML structure.
How can I solve this issue?
this should help
private string content;
[XmlText]
public string Content
{
get { return content; }
set { content = XElement.Parse(value).Value; }
}
First declare a property as XmlCDataSection
public XmlCDataSection ProjectXml { get; set; }
in this case projectXml is a string xml
ProjectXml = new XmlDocument().CreateCDataSection(projectXml);
when you serialize your message you will have your nice format (notice )
<?xml version="1.0" encoding="utf-16"?>
<MessageBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Message_ProjectStatusChanged">
<ID>131</ID>
<HandlerName>Plugin</HandlerName>
<NumRetries>0</NumRetries>
<TriggerXml><![CDATA[<?xml version="1.0" encoding="utf-8"?><TmData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="9.0.0" Date="2012-01-31T15:46:02.6003105" Format="1" AppVersion="10.2.0" Culture="en-US" UserID="0" UserRole=""><PROJECT></PROJECT></TmData>]]></TriggerXml>
<MessageCreatedDate>2012-01-31T20:28:52.4843092Z</MessageCreatedDate>
<MessageStatus>0</MessageStatus>
<ProjectId>0</ProjectId>
<UserGUID>8CDF581E44F54E8BAD60A4FAA8418070</UserGUID>
<ProjectGUID>5E82456F42DC46DEBA07F114F647E969</ProjectGUID>
<PriorStatus>0</PriorStatus>
<NewStatus>3</NewStatus>
<ActionDate>0001-01-01T00:00:00</ActionDate>
</MessageBase>
Most of the solutions presented in StackOverflow works only for Serialization, and not Deserialization. This one will do the job, and if you need to get/set the value from your code, use the extra property PriceUrlByString that I added.
private XmlNode _priceUrl;
[XmlElement("price_url")]
public XmlNode PriceUrl
{
get
{
return _priceUrl;
}
set
{
_priceUrl = value;
}
}
[XmlIgnore]
public string PriceUrlByString
{
get
{
// Retrieves the content of the encapsulated CDATA
return _priceUrl.Value;
}
set
{
// Encapsulate in a CDATA XmlNode
XmlDocument xmlDocument = new XmlDocument();
this._priceUrl = xmlDocument.CreateCDataSection(value);
}
}

Categories