NealR
NealR

Reputation: 10669

Obtain XML child nodes using C#

This is my first time attempting to parse XML using C# and feel like I'm running in circles right now. I am calling a WCF web service which, based upon user input, conducts a search through a database against company names. It returns the results in an XML document with each entry formatted as it is below.

Given this XML structure, how would I go about obtaining the values for the d:AccountId and d:Name nodes using C#?

<entry>
    <id></id>
    <title type=\"text\"></title>
    <updated></updated>
    <author><name /></author>
    <link rel=\"edit\" title=\"Account\" href=\"AccountSet\" />
    <category term=\"Microsoft.Crm.Sdk.Data.Services.Account\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />
    <content type=\"application/xml\">
    <m:properties>
        <d:neu_UniqueId></d:neu_UniqueId>
        <d:AccountId m:type=\"Edm.Guid\"></d:AccountId>
        <d:Name></d:Name>
    </m:properties></content>
</entry>

Here is my first attempt. The program threw an exception at the node3 variable.

        try
        {
            WebRequest myWebRequest = WebRequest.Create(URL);
            myWebRequest.PreAuthenticate = true;
            myWebRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;

            //myWebRequest.Headers.Add("Access-Control-Allow-Origin", url);

            WebResponse myWebResponse = myWebRequest.GetResponse();
            Stream myFileStreamResult = myWebResponse.GetResponseStream();
            Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
            StreamReader readStream = new StreamReader(myFileStreamResult, encoder);

            results = readStream.ReadToEnd();

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(results);
            XmlNodeList parentNode = xmlDoc.GetElementsByTagName("entry");

            foreach (XmlNode childNode in parentNode)
            {

                string node = childNode.ToString();
                string node2 = childNode.Value;
                string node3 = childNode.Attributes["title"].Value;
                string node7 = childNode.Attributes["m:properties"].Value;
                string node8 = childNode.Attributes["m:properties\\d:AccountId"].Value;
                string node9 = childNode.Attributes["m:properties\\d:Name"].Value;
                string node10 = childNode.Attributes["m:properties\\d:AccountId"].Value;
            }

        }

Upvotes: 2

Views: 33280

Answers (2)

Primary Key
Primary Key

Reputation: 1237

using Linq2Xml will probably be a little easier.

var xml = "<entry xmlns:m=\"ns1\" xmlns:n=\"ns2\" xmlns:d=\"ns3\">" +
 "<id></id>" +
 "<title type=\"text\"></title>" +
 "<updated></updated>" +
 "<author><name /></author>" +
 "<link rel=\"edit\" title=\"Account\" href=\"AccountSet\" />" +
 "<category term=\"Microsoft.Crm.Sdk.Data.Services.Account\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />" +
 "<content type=\"application/xml\">" +
 "<m:properties>" +
     "<d:neu_UniqueId></d:neu_UniqueId>" +
     "<d:AccountId m:type=\"Edm.Guid\">Account ID</d:AccountId>" +
     "<d:Name>Account Name</d:Name>" +
 "</m:properties></content>" +
"</entry>";

        const string namespaceM = "ns1";
        const string namespaceD = "ns3";

        using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
        {
            using (var reader = XmlReader.Create(stream))
            {
                var document = XDocument.Load(reader, LoadOptions.None);
                var contentNode = document.Elements().First().Elements().First(e => e.Name.LocalName == "content");
                var propertiesNode = contentNode.Elements().First(d => d.Name.LocalName == "properties" && d.Name.Namespace == namespaceM);
                var accountIdNode = propertiesNode.Elements().First(d => d.Name.LocalName == "AccountId" && d.Name.Namespace == namespaceD);
                var nameNode = propertiesNode.Elements().First(d => d.Name.LocalName == "Name" && d.Name.Namespace == namespaceD);
                var accountIdText = accountIdNode.Value;
                var nameText = nameNode.Value;
            }
        }

Upvotes: 2

evanmcdonnal
evanmcdonnal

Reputation: 48076

Assuming the API reliably returns that XML structure you can simply specify the path to the node as "/entry/m:properties" then call get children. After that you'll want to loop over those nodes, checking for the nodes you want.

Currently your foreach loop is attempting all of those operations on the <id></id> node which causes an Exception because there is no "title" attribute.

So to give some sample code, you're looking for something like this;

XmlNode props = root.SelectSingleNode("/entry/m:properties");
for (int i = 0; i < props.ChildNodes.Count; i++)
{
    if (propes.ChildNodes[i].Name = "node I want")
    {
         //do something
    }
}

Or if you specifically only want those two values, then just use SelectSingleNode with the full path to that node. From your question it sounds like there is no reason to use iteration. So you could simply do;

   string accountName = root.SelectSingleNode("/entry/m:properties/d:Name").InnerXml;

to get the account name.

Upvotes: 2

Related Questions