Reputation: 411
I have the following
`<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>1</name>
<value>
<struct>
<member>
<name>imageID</name>
<value>
<string>40087</string>
</value>
</member>
<member>
<name>imageURL</name>
<value> <string>http://local.server.gr/public_html/main/phpthumb/phpThumb.php?id=40087</string>
</value>
</member>
</struct>
</value>
</member>
<member>
<name>2</name>
<value>
<struct>
<member>
<name>imageID</name>
<value>
<string>40088</string>
</value>
</member>
<member>
<name>imageURL</name>
<value>
<string>http://local.server.gr/public_html/main/phpthumb/phpThumb.php?id=40088</string>
</value>
</member>
</struct>
</value>
</member>
<member>
<name>3</name>
<value>
<struct>
<member>
<name>imageID</name>
<value>
<string>40089</string>
</value>
</member>
<member>
<name>imageURL</name>
<value>
<string>http://local.server.gr/public_html/main/phpthumb/phpThumb.php?id=40089</string>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>`
xmlrpc response from a server.
I have tried different types of objects that accept and successfully serialize this xml but not with success. I cannot understand the "name" element that changes integer values. Any help is appreciated.
Upvotes: 1
Views: 2357
Reputation: 411
After considering your answers, the dynamic keyword make me think of this solution that is not perfect but does its work. I make return type of the method dynamic and then analyse with the visual studio debugger the dynamic object at run time. Then i construct this class:
public class ImageListResult
{
public List<ImageSlot> Slots { get; set; }
public ImageListResult(dynamic res)
{
this.Slots = new List<ImageSlot>();
try {
int keys = res.Keys.Count;
int values = res.Values.Count;
if (keys == values)
{
for (int i = 0; i < keys; i++)
{
ImageSlot slot = new ImageSlot()
{
Index = int.Parse(res.Keys[i])
};
int subCount = res.Values[i].Keys.Count;
for (int j = 0; j < subCount; j++)
{
string k = res.Values[i].Keys[j];
string v = res.Values[i].Values[j];
if (k.ToLower().Trim() == "imageid")
{
slot.ImageId = v;
}
else if(k.ToLower().Trim() == "imageurl")
{
slot.ImageUrl = v;
}
}
this.Slots.Add(slot);
}
}
}catch(Exception ex)
{
}
}
public class ImageSlot
{
/// <summary>
/// το index του image slot, απο το 1 εως το 25
/// </summary>
public int Index { get; set; }
public string ImageId { get; set; }
public string ImageUrl { get; set; }
}
}
so i successfully managed to deserialize the response. Its not ideal but its OK. If anyone think of a better solution feel free to post it, thanks for your answers
Upvotes: 0
Reputation: 34421
Try xml linq. Works real nice in this case
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication33
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("struct").FirstOrDefault().Elements("member").Select(x => new {
name = (int)x.Element("name"),
imageID = x.Descendants("member").Where(y => (string)y.Element("name") == "imageID").Select(z => (int)z.Descendants("string").FirstOrDefault()).FirstOrDefault(),
imageURL = x.Descendants("member").Where(y => (string)y.Element("name") == "imageURL").Select(z => (string)z.Descendants("string").FirstOrDefault()).FirstOrDefault(),
}).ToList();
}
}
}
Into a class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication33
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Image.images = doc.Descendants("struct").FirstOrDefault().Elements("member").Select(x => new Image() {
name = (int)x.Element("name"),
imageID = x.Descendants("member").Where(y => (string)y.Element("name") == "imageID").Select(z => (int)z.Descendants("string").FirstOrDefault()).FirstOrDefault(),
url = x.Descendants("member").Where(y => (string)y.Element("name") == "imageURL").Select(z => (string)z.Descendants("string").FirstOrDefault()).FirstOrDefault(),
}).ToList();
}
}
public class Image
{
public static List<Image> images { get; set; }
public int name { get; set; }
public int imageID { get; set; }
public string url { get; set; }
}
}
Upvotes: 0
Reputation: 131591
XML-RPC was created by Microsoft and superseded by SOAP before the first .NET version in 2002. The trouble with it is that you have no idea what the actual objects' schema is. XML-RPC is similar to Json, it serializes everything as name/value items that could be used to reconstruct an object's properties. You have no idea though what all those properties are.
What you can do, is deserialize the elements so that you can read them at least. Luckily, XML-RPC was used by Frontpage and its usage survived with SharePoint. This means there is a ready-made schema you can use here.
You can generate C# classes from it using the old xsd.exe
program. Save the schema to a file (eg xmlrpc.xsd), ensure there are no whitespaces before the tag and use the following line to generate the classes :
xsd xmlrpc.xsd /c /nx:XlmRpcNS
where XmlRpcNS
is the namespace you want to use for the generated classes. Add the generated file to your project (by default it's xmlrpc.cs
) and use them to deserialize the response, eg:
using (var reader = new StringReader(response))
{
var sz = new XmlSerializer(typeof(methodResponse));
var methodResponse= (methodResponse)sz.Deserialize(reader);
var content = (methodResponseParams)methodResponse.Item;
var structContent = (StructType)content.param.value.Item;
//...
}
The problem is that xsd.exe
generates an object Item
property for each choice element, which is why you need to cast to the proper type.
Another option is to use dynamic
to avoid the casts. You lose Intellisens this way though:
dynamic methodResponse= (methodResponse)sz.Deserialize(reader);
var members = methodResponse.Item.param.value.Item;
Upvotes: 1