Check for existence of XML node using LINQ

Hi,

I'm not very familiar with LINQ but this might be relatively simple.

I have an XML file (Test1.xml) like

<Test>
   <FirstName>Test</FirstName>
   <LastName>LastTest</LastName>
   <SSN>123456789</SSN>
   <State>OH</State>
   <LandLine>1112223456</LandLine>
   <VOIP>9876543211</VOIP>
</Test>
 
But I have another XML (Test2.xml) like:

<Test>
   <FirstName>Testa</FirstName>
   <LastName>LastTest2</LastName>
   <SSN>192837465</SSN>
   <State>CO</State>
   <LandLine>1112223457</LandLine>
</Test>

The VOIP does not exist in the second example.

I can go through the directory and get each of the files.

But I'm not too sure how to use LINQ to check for the existence of the node and how if it exists to check to see if it contains like a "654".

How can that be done? I'm using C#.

Any information would be greatly appreciated.

Thanks
LVL 1
davismAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MicMaticCommented:
var query = 
from test in Xml.Descendants("Test")

let attributes = book.Element("VOIP")


select .......;

Open in new window


let attributes = book.Element("VOIP") ==> will return true if it exists
0
MicMaticCommented:
small edit: line 4 should be: let attributes = query.Element("VOIP")
0
davismAuthor Commented:
Get a compilation error. Cannot use local variable 'query' before it's declared.

And that is with the Line 4 edit.

Is there something else?
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

prakash_prkCommented:
There is no special thing to do . Just check the element is null or not.

 
XDocument test1Xml = XDocument.Load(@"E:\EE\Test1.xml");
XDocument test2Xml = XDocument.Load(@"E:\EE\Test2.xml");

if (IsVOIPValue(test1Xml, "654"))
{
    MessageBox.Show("Test1");
}

if (IsVOIPValue(test2Xml, "654"))
{
    MessageBox.Show("Test2");
}

public bool IsVOIPValue(XDocument document, string value)
{
    if (document.Root.Element("VOIP") != null)
    {
        return string.Compare(document.Root.Element("VOIP").Value, value, StringComparison.InvariantCultureIgnoreCase) == 0;
    }

    return false;
}

Open in new window


0
davismAuthor Commented:
But is there a way to do this with LINQ?

I'm looking at attempting to get a better understanding of LINQ to XML.
0
MicMaticCommented:
sorry, my bad (it's still early for me :-), the correct code should be:

var query = 
  from test in Xml.Descendants("Test")
  let attributes = test.Element("VOIP")
  select attributes;

Open in new window

0
prakash_prkCommented:
The task you wanted to do is a very simple thing. The classes used here are the Linq To Xml Classes.

XDocument - Is the basic document xml class in XLinq.

The XLinq can be used in many contexts. You can create a Xml and search for a content in xml. And transforming Xml, .....

I just answered the question you asked.  :)

0
MicMaticCommented:
damn, forgot 1 letter...

line 3: let attributes = test.Elements("VOIP")
0
prakash_prkCommented:
if you want to learn on XLinq then check tihs out...

http://www.hookedonlinq.com/
0
davismAuthor Commented:
MicMatic, what would be the check for the query? Because it's executing but the query variable doesn't have anything in it. Basically, showing the resultsview as empty and that's on both of the .xml's.

parkash_prk, thanks for the book reference. You mentioned, "The task you wanted to do is a very simple thing." But what I don't understand is how that is done.
0
MicMaticCommented:
Take a look at this page, it has some nice info about LINQ & XML: http://www.techrepublic.com/blog/programming-and-development/access-xml-data-using-linq-to-xml/594

I think you'll find what you need, the info is quite good, and there are some nice examples!
0
prakash_prkCommented:
oh ok. I will explain,

XDocument test1Xml = XDocument.Load(@"E:\EE\Test1.xml");

the above line will load the xml content from file to a XDocument object.

The XDocument Object represents your xml.
 
XDocument.Root -> points to the root node of the xml. In our Xml it points to "<Test>" node.

the FirstName, LastName,... all are children of the Test node. To access the children node you should use the Element() method of the XNode ( XElement, XDocument) are children of XNode.

check "XLINQ Classes" in the following link to see the class hierarchy diagram
http://www.codeproject.com/kb/vista/LINQ_3.aspx?PageFlow=Fluid

document.Root.Element("VOIP") -> that line gets the VOIP node. after that just check the value of the node.

Thanks & Regards
Prakash

0
tpaynCommented:
You can cast the elements as string. Check for null to indicate an absent element.

e.g.

   
private void TestXmlLinq
        {
            const string xml1 = @"<Test>
                                    <FirstName>Test</FirstName>
                                    <LastName>LastTest</LastName>
                                    <SSN>123456789</SSN>
                                    <State>OH</State>
                                    <LandLine>1112223456</LandLine>
                                    <VOIP>9876543211</VOIP>
                                </Test>";
            const string xml2 = @"<Test>
                                    <FirstName>Testa</FirstName>
                                    <LastName>LastTest2</LastName>
                                    <SSN>192837465</SSN>
                                    <State>CO</State>
                                    <LandLine>1112223457</LandLine>
                                </Test>";

            using (TextReader reader = new StringReader(xml2))
            {
                XDocument testxml = XDocument.Load(reader);
                var people = from person in testxml.Descendants("Test") select new { FirstName = (string)person.Element("FirstName"), Voip = (string)person.Element("VOIP") };
                foreach (var person in people)
                    if (string.IsNullOrEmpty(person.Voip))
                    {
                        // element or value missing
                    }
                    else
                        if (person.Voip == "654")
                        {
                            // value == 654
                        }
            }

        }

Open in new window

0
davismAuthor Commented:
Or does it depend on the structure of the XML as well? Albeit, I'm not sure how it would all the elements are based of Descendants("test"). If the VOIP is a childnode of it or somewhere further down in the XMLNode tree...is there a difference there?

In one, something like:

<Test>
   <FirstName>Test</FirstName>
   <LastName>LastTest</LastName>
   <SSN>123456789</SSN>
   <State>OH</State>
   <LandLine>1112223456</LandLine>
   <VOIP>9876543211</VOIP>
</Test>

In another something like:

<Test>
   <FirstName>Test</FirstName>
   <LastName>LastTest</LastName>
   <SSN>123456789</SSN>
   <State>OH</State>
   <Phone>
       <LandLine>1112223456</LandLine>
       <VOIP>9876543211</VOIP>
   <Phone>
</Test>



0
Fernando SotoRetiredCommented:
Hi davism;

Here is a code snippet that will check for a VOIP node and see if it contains 654. If it does it returns true otherwise it returns false.

string[] test = { System.IO.File.ReadAllText(@"C:\Temp\test1.xml"), 
                      System.IO.File.ReadAllText(@"C:\Temp\test2.xml")};

foreach( string xmlText in test )
{	
	XDocument xdoc = XDocument.Parse(xmlText);
	XElement root = xdoc.Root;

	bool has654 = (from voip in root.Descendants()			 
    	           select voip).Any( v => v.Name == "VOIP" && v.Value.Contains("654"));
			  
	Console.WriteLine(has654);		
}

Open in new window


Fernando
0
davismAuthor Commented:
FernandoSoto, that doesn't seem to work. I am always getting a "false".
0
davismAuthor Commented:
Actually, that is working with that sample but for some reason it's not working on the XML that I am using.
0
Fernando SotoRetiredCommented:
Hi davism;

I tested the code with your sample data before posting with no issues. If the VOIP node exist but does NOT have the three digits 654 it will return False or if no VOIP node does not exist it will return False only if VOIP node has 654 in its inner text as this one. <VOIP>9876543211</VOIP>, it will return true.

Please post your code even if you copied and past.

Fernando
0
Fernando SotoRetiredCommented:
Then please post the code your are using and the sample that it is not working with.
0
davismAuthor Commented:
Interesting... The very first node...or root node... <Test> if I just use that but if I use it with xmlnamespaces it does not.

It there a way to work with the namespaces?
0
Fernando SotoRetiredCommented:
Yes Linq to XML obeys the rules of XML so if a name space is used you need to use it as well in the query. Also be aware that XML is case sensitive so "VOIP" does not equal "voip".

foreach( string xmlText in test )
{	
    Document xdoc = XDocument.Parse(xmlText);
    Element root = xdoc.Root;
    // Add this line
    Namespace ns = root.GetDefaultNamespace();
    
    // Modify the select line with ns + before "VIOP"
    bool has654 = (from voip in root.Descendants()
                   select voip).Any( v => v.Name == ns + "VOIP" && v.Value.Contains("654"));
    		  
    Console.WriteLine(has654);		
}

Open in new window

0
davismAuthor Commented:
That new line:

// Add this line
    Namespace ns = root.GetDefaultNamespace();

is giving me an error:

The type of namespace "Namespace" could not be found...

What would be the cause of that?  
0
Fernando SotoRetiredCommented:
Sorry that should read as follows:

XNamespace ns = root.GetDefaultNamespace();
0
davismAuthor Commented:
That doesn't seem to be doing much either though.

The first node or root is like this:

<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" TestID="Apple"  ID="1" xmlns="urn:Finite.List.Test">

0
Fernando SotoRetiredCommented:
I just inserted the root node you just posted into the XML documents and it worked just fine.

Can you post your source code please.
0
davismAuthor Commented:
What I have is this:

string[] test = { (System.IO.File.ReadAllText(@"C:\Temp\test1.xml"))};
                    foreach( string xmlText in test )
                    {      
                          XDocument xdoc = XDocument.Parse(xmlText);
                          XElement root = xdoc.Root;
                        // Add this line
                        XNamespace ns = root.GetDefaultNamespace();

                        bool has654 = (from Phone in root.Descendants()
                                       select Phone).Any(v => v.Name == "PhoneNumber" && v.Value.Contains("("));
                    
                          Console.WriteLine(has654);
                    }

It's pretty much the same as what you provided. However, it's always back with a false.
0
Fernando SotoRetiredCommented:
Except for the fact that a variable name changed and you are looking for a "(" with the Contains method the two lines below are almost the same.

// This line is what I posted
select voip).Any( v => v.Name == ns + "VOIP" && v.Value.Contains("654"));
// This is the line from your code, something is missing
select Phone).Any(v => v.Name == "PhoneNumber" && v.Value.Contains("("));

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Fernando SotoRetiredCommented:
Does it work for you now?
0
davismAuthor Commented:
Oh my...where/how did I miss that ns + statement. I was wondering where the XNamespace ns comes in other than just defining it.

So far so good. Let me just continue on the testing to make sure before I award you the points.

Will provide info soon.

Thanks!
0
Fernando SotoRetiredCommented:
Not a problem, just wanting to make sure you were moving on.
0
Fernando SotoRetiredCommented:
Hi davism;

If this issue is resolved please close the question.

Thanks;
Fernando
0
davismAuthor Commented:
Everything is working out great! Thank you very much and great information!
0
Fernando SotoRetiredCommented:
Not a problem, glad that It worked out for you.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.