Link to home
Start Free TrialLog in
Avatar of schubduese
schubdueseFlag for Switzerland

asked on

Read XML with Linq (the second)

I try to read the following XML Structure with Linq (yes, newbie here :) )

  <registry>
    <exclude_pcs>
      <pc></pc>
    </exclude_pcs>
    <detail></detail>
    <keys>
      <key>HKLM\Software\Microsoft\Windows\CurrentVersion\Run</key>
      <key>HKLM\Software</key>
    </keys>
  </registry>

My Code returns both values, but in one single string (HKLM\Software\Microsoft\Windows\CurrentVersion\Run\HKLM\Software)

What am I doing wrong?
This is what I am doing at the moment:
 
List<Object> keysSet = new List<Object>;
 
XElement configXML = XElement.Load(xmlFileName);
 
           var reg = configXML.Elements("registry");
 
            // Go through nodes
            foreach (XElement regNodes in reg)
            {
 
                // Keys
                var q = from c in regNodes.Descendants("keys")
                        select c;
 
                if (q.Count() > 0)
                {
                    foreach (String key in q)
                    {
                        if (! string.IsNullOrEmpty(key))
                        {
                            keysSet.Add(key);
                        }
                    }
                }
}

Open in new window

Avatar of abel
abel
Flag of Netherlands image

You are looping through the keys, not through the keys/key collection. Try:

var q = from c in regNodes.Descendants("key")                        select c;
instead.

btw, your code does not compile, the first line misses parentheses ()
Avatar of Dirk Haest
You just need to change your linq-query

                // Keys
                var q = from c in regNodes.Descendants("key")
                        select c;
Avatar of schubduese

ASKER

I know the code is not compiling, it's just an extract of the code... :)

thanks again abel
Btw, since you placed this question on the LINQ Zone, what about making your code a bit easier by using LINQ? See snippet (tested and works with your source XML):

var reg = configXML.Elements("registry");
 
// Go through nodes
foreach (string keyValues in 
    from key in configXML.DescendantsAndSelf() 
    where key.Name == "key" 
    select key.Value)
{
 
    keysSet.Add(keyValues);
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of abel
abel
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi schubduese;

This code will get all the key values from the key node and place them into the List.

Fernando
// The list returned from query is of type string
List<String> keysSet = new List<String>();
// Load the XML document into a XElement structure
XElement configXML = XElement.Load(xmlFileName);
 
// Query the XML document for all the key nodes within the parent node keys
// and do not select those nodes with a inner text value of empty string and
// place the selected values into the List<String> keySet
keysSet = (from k in configXML.Descendants("keys").Descendants("key")
           where k.Value != String.Empty
           select k.Value).ToList();
 
// Display the values in the keySet
foreach (string key in keysSet)
{
    Console.WriteLine("Key = " + key);
}

Open in new window

great! thanks abel, that's fantastic!
As fernando has showed, if you have <key></key> in your data that you do not want to include, you can add the "where key.Value != String.Empty" to the command:

keysSet.AddRange(from key in configXML.DescendantsAndSelf()
                 where key.Name == "key" and key.Value != String.Empty
                 select (object) key.Value);

Open in new window

Hi schubduese;

Please note that the solution by abel will select all nodes that have the name key no matter where it is in the document even if it is a child of a different node and not a child of the node keys.

Fernando
That is entirely correct. But I took the liberty to take the input XML. Using the Descendants("keys").Descendants("key") you will make sure that they are a descendant to keys. Still, that doesn't help if you XML looks like this:

<keys>
     <specialkeys>
          <key>....</key>
     </specialkeys>
     <key>.....</key>
</keys>
because then both the special keys and the normal keys will get selected. If you need a better selection from your XML if the <key> can also appear on different levels and you do not want to include those, show a bit of the XML and we will help you further with it.