Well, since this question is going Tumbleweed, I'll post the answer I found on my own...
I found this (among others) which helped with the foundations of .NET XML serialization/deserialization. I tried using xsd.exe
, but the results were disappointing. But starting from that base, I created a CLR type for the XML feed:
[XmlRoot("search")]
public class SearchTag
{
[XmlAttribute("ver")]
public string ver { get; set; }
[XmlElement("loc")]
public SearchLocTag[] loc { get; set; }
}
public class SearchLocTag
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlAttribute("type")]
public string type { get; set; }
[XmlText]
public string text { get; set; }
}
The default serializer XMLMediaTypeFormatter uses (DataContractSerializer) did undesirable things with tag names and inserted unwanted XmlSerializerNamespaces info. But I found this and created a custom XmlObjectSerializer:
public class SearchSerializer : XmlObjectSerializer
{
XmlSerializer serializer;
public SearchSerializer()
{
this.serializer = new XmlSerializer(typeof(SearchTag));
}
public override void WriteObject(XmlDictionaryWriter writer, object graph)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
serializer.Serialize(writer, graph, ns);
}
public override bool IsStartObject(XmlDictionaryReader reader)
{
throw new NotImplementedException();
}
public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
{
throw new NotImplementedException();
}
public override void WriteEndObject(XmlDictionaryWriter writer)
{
throw new NotImplementedException();
}
public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
{
throw new NotImplementedException();
}
public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
{
throw new NotImplementedException();
}
}
Then added this to Global.asax.cs:
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SetSerializer<SearchTag>(new SearchSerializer());
Then the controller became:
public class SearchController : ApiController
{
public HttpResponseMessage Get(string location)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://wxdata.weather.com");
HttpResponseMessage response = client.GetAsync(String.Format("wxdata/search/search?where={0}", location)).Result;
response.EnsureSuccessStatusCode();
var stream = response.Content.ReadAsStreamAsync().Result;
var serializer = new XmlSerializer(typeof(SearchTag));
using (var reader = new XmlTextReader(stream))
{
if (serializer.CanDeserialize(reader))
{
var xmlData = (SearchTag)serializer.Deserialize(reader);
return Request.CreateResponse<SearchTag>(HttpStatusCode.OK, xmlData);
}
else
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
}
}
}
The resulting application/xml messages:
Request
GET http://localhost:53047/twc/search/london HTTP/1.1
User-Agent: Fiddler
Accept: application/xml
Host: localhost:53047
Response
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcQ2xheXRvblxEb2N1bWVudHNcVmlzdWFsIFN0dWRpbyAyMDEzXFByb2plY3RzXFR3Y0FwaVx0d2Ncc2VhcmNoXGxvbmRvbg==?=
X-Powered-By: ASP.NET
Date: Wed, 04 Dec 2013 21:42:46 GMT
Content-Length: 484
<search ver="3.0"><loc id="UKXX0085" type="1">London, GLA, United Kingdom</loc><loc id="USAL2905" type="1">London, AL</loc><loc id="USAR0340" type="1">London, AR</loc><loc id="USCA9301" type="1">London, CA</loc><loc id="USIN2109" type="1">London, IN</loc><loc id="USKY1090" type="1">London, KY</loc><loc id="USMI2014" type="1">London, MI</loc><loc id="USMN2182" type="1">London, MN</loc><loc id="USMO2769" type="1">London, MO</loc><loc id="USOH0520" type="1">London, OH</loc></search>
And the resulting application/json messages:
Request
GET http://localhost:53047/twc/search/london HTTP/1.1
User-Agent: Fiddler
Accept: application/json
Host: localhost:53047
Response
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcQ2xheXRvblxEb2N1bWVudHNcVmlzdWFsIFN0dWRpbyAyMDEzXFByb2plY3RzXFR3Y0FwaVx0d2Ncc2VhcmNoXGxvbmRvbg==?=
X-Powered-By: ASP.NET
Date: Wed, 04 Dec 2013 21:43:18 GMT
Content-Length: 528
{"ver":"3.0","loc":[{"id":"UKXX0085","type":"1","text":"London, GLA, United Kingdom"},{"id":"USAL2905","type":"1","text":"London, AL"},{"id":"USAR0340","type":"1","text":"London, AR"},{"id":"USCA9301","type":"1","text":"London, CA"},{"id":"USIN2109","type":"1","text":"London, IN"},{"id":"USKY1090","type":"1","text":"London, KY"},{"id":"USMI2014","type":"1","text":"London, MI"},{"id":"USMN2182","type":"1","text":"London, MN"},{"id":"USMO2769","type":"1","text":"London, MO"},{"id":"USOH0520","type":"1","text":"London, OH"}]}
Which is exactly what I was after.