0

I'm trying to parse the xml-response from the amazon api.

This is a part of the received xml-file:

<BrowseNodeLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
  <OperationRequest>
    <RequestId>31317fca-ad3d-4ff0-a64f-693c0e44959b</RequestId>
    <Arguments>
      <Argument Name="Operation" Value="BrowseNodeLookup" />
      <Argument Name="Service" Value="AWSECommerceService" />
      <Argument Name="Version" Value="2011-08-01" />
      <Argument Name="BrowseNodeId" Value="186606" />
      <Argument Name="Timestamp" Value="2015-01-04T11:50:06Z" />
      <Argument Name="ResponseGroup" Value="BrowseNodeInfo" />
    </Arguments>
    <RequestProcessingTime>0.002221</RequestProcessingTime>
  </OperationRequest>
  <BrowseNodes>

I want to read the Argument Timestamp. This is my code, but it only work if I remove the xmlns attribute in the xml-file.

    Dim nodeTimestamp As XmlNode = doc.SelectSingleNode("/BrowseNodeLookupResponse/OperationRequest/Arguments/Argument[@Name='Timestamp']")

    Dim text As String = nodeTimestamp.Attributes.ItemOf("Value").InnerText
keenthinker
  • 7,405
  • 2
  • 36
  • 45
Jimmy09
  • 1
  • 2
  • This is a very frequently asked question. The answer is to use an `XmlNamespaceManager` and declare a prefix for that Amazon namespace. – Tomalak Jan 04 '15 at 13:23

1 Answers1

0

I suppose you receive a valid XML from amazon (the last closing tag is </BrowseNodeLookupResponse>. You can use LINQ2XML in order to select the value of the desired value attribute. You need to take the default namespace and use it when accessing and searching for specific elements / nodes in the XML. For the example I have saved your XML input in a file called axml.xml:

' load the xml. Use XDocument.Parse to load a XML-Structure from a String!
Dim xml as XDocument = XDocument.Load("c:\temp\axml.xml")
' get the namespace for later use
Dim ns = xml.Root.GetDefaultNamespace()
' find the Arguments node, holding all Argument nodes. Note the use of the namespace
Dim arguments = xml.Root _
    .Descendants(ns + "Arguments") _ 
    .Elements(ns + "Argument")
' find and take the Argument node with the specified name
Dim ts = from argument in arguments
         where argument.Attribute("Name").Value = "Timestamp"
         select argument
' take the value of the desired attribute
Console.WriteLine(ts.FirstOrDefault().Attribute("Value").Value)

The output is:

2015-01-04T11:50:06Z

If you want to stick to the XmlDocument approach, you need to use the XmlDocumentNamespaceManager (as shown in this SO post) in order to retrieve the node using the namespace. A solution could look like this:

Dim xml = new XmlDocument()
xml.Load("c:\temp\axml.xml")
Dim xmlnsManager = new XmlNamespaceManager(xml.NameTable)
' take the custom namespace and add it to the namespace manager
xmlnsManager.AddNamespace("custom", xml.ChildNodes(0).Attributes("xmlns").Value)
' find the desired node
Dim nodeTimestamp = xml.SelectSingleNode("//custom:Arguments/custom:Argument[@Name='Timestamp']", xmlnsManager)
' and take the attribute value
Console.WriteLine(nodeTimestamp.Attributes("Value").Value)

The output is the same as above.

Community
  • 1
  • 1
keenthinker
  • 7,405
  • 2
  • 36
  • 45
  • Thanks for your answer. I will try it with Linq to, because I use it for other things in my project, too. I wondering whats the sense of a namespacemanager, since I saw the demo code on amazon. Now I know, with a namespacemanager my code works to. – Jimmy09 Jan 04 '15 at 12:53
  • I have added a solution that uses XmlDocument as in your example. – keenthinker Jan 04 '15 at 13:21
  • @Tomalak Thanks for the remark - you are rigtht, I have removed the `PushScope`. About the empty prefix - it did not worked. – keenthinker Jan 04 '15 at 13:36
  • You are right, it requires a prefix. I was mistaken. On a different note, I consider blindly taking the default `xmlns` value from the XML document itself a mistake. XML namespaces are part of the contract, they ought to be hard-coded. I'd do this: http://pastebin.com/ELyPeEtW – Tomalak Jan 04 '15 at 13:47
  • @Tomalak You are right about the hard-coded prefixes, I just wanted to have less copy/paste. Your solution is elegant and simpler than mine. – keenthinker Jan 04 '15 at 14:22