Serialize/Deserialize POCO’s

Short and easy way to to generically Serialize/Deserialize objects.

  1. public static string SerializeToXml<T>(T value)
  2. {
  3.     StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
  4.     XmlSerializer serializer = new XmlSerializer(typeof(T));
  5.     serializer.Serialize(writer, value);
  6.     return writer.ToString();
  7. }
  8.  
  9. public static T DeserializeFromXml<T>(string xml)
  10. {
  11.     StringReader reader = new StringReader(xml);
  12.     XmlSerializer serializer = new XmlSerializer(typeof(T));
  13.     return (T)serializer.Deserialize(reader);
  14. }


Usage:

  1. MyObject myObj = new MyObject();
  2. string xmlAsString = SerializeToXml(myObj);
  3. MyObject newMyObj = DeserializeFromXml<MyObject>(xmlAsString);

Amazon, XML, XPath and C# 2.0

I am putting this out there so that, hopefully, no one else will struggle like I just did.

I am trying to use XPath to parse the results from one of the Amazon Web Services. I was not expecting this to be difficult, and it really is not, if you know how to use XPathNavigator. As it turns out, I did not how to use it well.

So first things first… here is an “edited” snippet of the XML response that the Amazon Web Service will return if you are doing a keyword search on “dune”.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
  3. <OperationRequest>
  4. <HTTPHeaders>
  5. <Header Name="UserAgent" Value="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1"></Header>
  6. </HTTPHeaders>
  7. <RequestId>0RBC1MZYXZQMQG6FFPCF</RequestId>
  8. <Arguments>
  9. <Argument Name="Keywords" Value="dune"></Argument>
  10. <Argument Name="ResponseGroup" Value="ItemAttributes"></Argument>
  11. <Argument Name="Operation" Value="ItemSearch"></Argument>
  12. <Argument Name="Service" Value="AWSECommerceService"></Argument>
  13. <Argument Name="AWSAccessKeyId" Value="02BQRV88E94VXX9GGY02"></Argument>
  14. <Argument Name="SearchIndex" Value="Books"></Argument>
  15. </Arguments>
  16. <RequestProcessingTime>0.110208988189697</RequestProcessingTime>
  17. </OperationRequest>
  18. <Items>
  19. <Request>
  20. <IsValid>True</IsValid>
  21. <ItemSearchRequest>
  22. <Keywords>dune</Keywords>
  23. <ResponseGroup>ItemAttributes</ResponseGroup>
  24. <SearchIndex>Books</SearchIndex>
  25. </ItemSearchRequest>
  26. </Request>
  27. <TotalResults>1394</TotalResults>
  28. <TotalPages>140</TotalPages>
  29. <Item>
  30. <ASIN>0441172717</ASIN>
  31. <DetailPageURL>http://www.amazon.com/…</DetailPageURL>
  32. <ItemAttributes>
  33. <Author>Frank Herbert</Author>
  34. <Binding>Paperback</Binding>
  35. <EAN>9780441172719</EAN>
  36. <Edition>25th Anniv</Edition>
  37. <ISBN>0441172717</ISBN>
  38. <ListPrice>
  39. <Amount>799</Amount>
  40. <CurrencyCode>USD</CurrencyCode>
  41. <FormattedPrice>$7.99</FormattedPrice>
  42. </ListPrice>
  43. <NumberOfItems>1</NumberOfItems>
  44. <NumberOfPages>535</NumberOfPages>
  45. <PackageDimensions>
  46. <Height Units="hundredths-inches">88</Height>
  47. <Length Units="hundredths-inches">708</Length>
  48. <Weight Units="hundredths-pounds">55</Weight>
  49. <Width Units="hundredths-inches">428</Width>
  50. </PackageDimensions>
  51. <ProductGroup>Book</ProductGroup>
  52. <PublicationDate>1996-02</PublicationDate>
  53. <Publisher>ACE Charter</Publisher>
  54. <Title>Dune (Dune Chronicles, Book 1)</Title>
  55. </ItemAttributes>
  56. </Item>
  57. </Items>
  58. </ItemSearchResponse>

I want to cycle through each of the “ItemAttributes” parsing each and saving their values elsewhere. I initially tried the following:

  1. XPathDocument doc =
  2.     new XPathDocument(GetHttpWebResponse(url).GetResponseStream());
  3. XPathNavigator nav = doc.CreateNavigator();
  4. XPathNodeIterator iter =
  5.     nav.Select("/ItemSearchResponse/Items/Item/ItemAttributes");
  6.  
  7. while (iter.MoveNext())
  8. {
  9.     // process nodes here…
  10. }

No matter what XPath expression I would use in the “nav.Select()”, my iterator would be empty.

After several fruitless searches, I finally found this on the MSDN site that showed me what I was doing wrong.

I was in such a hurry to parse the XML response that I totally forgot about the XML Namespaces. Now that I knew what my problem was, it was an easy fix.

  1. XPathDocument doc =
  2.     new XPathDocument(GetHttpWebResponse(url).GetResponseStream());
  3. XPathNavigator nav = doc.CreateNavigator();
  4. XmlNamespaceManager manager = new XmlNamespaceManager(nav.NameTable);
  5. manager.AddNamespace("a", "http://webservices.amazon.com/AWSECommerceService/2005-10-05");
  6. XPathNodeIterator iter = nav.Select("/a:ItemSearchResponse/a:Items/a:Item/a:ItemAttributes");
  7.  
  8. while (iter.MoveNext())
  9. {
  10.     // process nodes here…
  11. }

Another example of why it pays not to be in a hurry and to read the API ;)