Obtain XML child nodes using C#

31,984

Solution 1

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.

Solution 2

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;
            }
        }
Share:
31,984
NealR
Author by

NealR

Updated on April 25, 2020

Comments

  • NealR
    NealR about 4 years

    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;
                }
    
            }
    
    • MarcinJuraszek
      MarcinJuraszek about 11 years
      m: and d: are namespaces. You should declare them first. Btw: Why don't you use LINQ to XML?
    • Alexei Levenkov
      Alexei Levenkov about 11 years
      All "Attributes" you mentioned in code are actually "elements". It may be useful to scan MSDN for basic samples first (or w3c.org/xml if you really into reading XML)...
  • NealR
    NealR about 11 years
    Would this path be used in the .Attributes method or .GetElementsByTagName?
  • evanmcdonnal
    evanmcdonnal about 11 years
    @NealR neither, you would use SelectNodes or SelectSingleNode in place of GetElementsBytTagName. I posted some sample code.
  • NealR
    NealR about 11 years
    What would the root variable correspond to in your code? I tried using my xmlDoc variable for this but got this error: Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.
  • evanmcdonnal
    evanmcdonnal about 11 years
    @NealR sorry my example wasn't very clear. Check the example here which has code to load the doc ect - msdn.microsoft.com/en-us/library/h0hw012b.aspx