How to get the value of an XML element using Linq, even if it is empty

Please excuse my stupidity, I am inclined to believe that XML intersection is too complicated.

I am using ASP.NET in VB.

I have an XML document that contains all the information about the staff of my company ...

<staff> <staffName>Test Staff</staffName> <staffTitle>Slave</staffTitle> <staffDepartmentName>Finance</staffDepartmentName> <staffOffice>London</staffOffice> <staffEmail> t.staff@company.co.uk </staffEmail> <staffPhone>0207 123 456</staffPhone> <staffNotes>Working hours Mon to Thurs 9.15 - 5.15</staffNotes> <staffBio></staffBio> </staff> 

As you can see, some nodes do not always contain data that has ever been employees; only directors have biographies.

I get access to such values ​​...

 For Each staff In ( _ From matches In myXMLFile.Descendants("staff").Descendants("staffName") _ Where matches.Nodes(0).ToString.ToLower.Contains(LCase(search)) _ Order By matches.Value _ Select matches) staffName = staff.Descendants("staffName").Nodes(0).ToString) staffTitle = staff.Descendants("staffTitle").Nodes(0).ToString) staffOffice = staff.Descendants("staffOffice").Nodes(0).ToString) staffEmail = staff.Descendants("staffEmail").Nodes(0).ToString) staffPhone = staff.Descendants("staffPhone").Nodes(0).ToString) staffNotes = staff.Descendants("staffNotes").Nodes(0).ToString) staffBio = staff.Descendants("staffBio").Nodes(0).ToString) ' Do something with that data... Next 

As soon as it gets to staffBio, I get the error message "The object reference is not installed in the object instance." obviously because node does not exist.

My question is, how can I assign a value to a variable, even when it is empty, without having to do a conditional check before each assignment?

+4
source share
2 answers

First, myXMLFile.Descendants("staff").Descendants("staffName") is redundant. Descendants return all elements at any level within an XDocument or XElement . So myXMLFile.Descendants("staffName") will give the same result.

Secondly, you can simply use the Element property and the Value property as follows:

 staffBio = staff.Element("staffBio").Value 

staff will have only one staffBio element, so there is no need to use the Descendants property. Value is a string, so you do not need to call Value.ToString . If the element is empty, then Value will return an empty string, and this is what you are looking for!

Thirdly, there is a much better (and I believe a more direct) way to do this in VB.NET. Here is a console application that demonstrates how to do this:

 Module Module1 Sub Main() Dim myXMLFile = <allStaff> <staff> <staffName>Test Staff</staffName> <staffTitle>Slave</staffTitle> <staffDepartmentName>Finance</staffDepartmentName> <staffOffice>London</staffOffice> <staffEmail> t.staff@battens.co.uk </staffEmail> <staffPhone>0207 123 456</staffPhone> <staffNotes>Working hours Mon to Thurs 9.15 - 5.15</staffNotes> <staffBio></staffBio> </staff> <staff> <staffName>Other Staff</staffName> <staffTitle>Master</staffTitle> <staffDepartmentName>IT</staffDepartmentName> <staffOffice>Oxford</staffOffice> <staffEmail> o.staff@battens.co.uk </staffEmail> <staffPhone>0207 123 789</staffPhone> <staffNotes></staffNotes> <staffBio>Some guy.</staffBio> </staff> </allStaff> Dim search = "Test" Dim searchQuery = From staff In myXMLFile...<staff> _ Where staff.<staffName>.Value.Contains(search) _ Select si = New StaffInfo With {.Name = staff.<staffName>.Value, _ .Title = staff.<staffTitle>.Value, _ .Department = staff.<staffDepartmentName>.Value, _ .Office = staff.<staffOffice>.Value, _ .Email = staff.<staffEmail>.Value, _ .Phone = staff.<staffPhone>.Value, _ .Notes = staff.<staffNotes>.Value, _ .Bio = staff.<staffBio>.Value} For Each staff In searchQuery Console.WriteLine("Name: {0}", staff.Name) Console.WriteLine("Title: {0}", staff.Title) Console.WriteLine("Department: {0}", staff.Department) Console.WriteLine("Office: {0}", staff.Office) Console.WriteLine("Email: {0}", staff.Email) Console.WriteLine("Phone: {0}", staff.Phone) Console.WriteLine("Notes: {0}", staff.Notes) Console.WriteLine("Bio: {0}", staff.Bio) Console.WriteLine() Next Console.ReadLine() End Sub Private Class StaffInfo Private _name As String Public Property Name() As String Get Return _name End Get Set(ByVal value As String) _name = value End Set End Property Private _title As String Public Property Title() As String Get Return _title End Get Set(ByVal value As String) _title = value End Set End Property Private _department As String Public Property Department() As String Get Return _department End Get Set(ByVal value As String) _department = value End Set End Property Private _office As String Public Property Office() As String Get Return _office End Get Set(ByVal value As String) _office = value End Set End Property Private _email As String Public Property Email() As String Get Return _email End Get Set(ByVal value As String) _email = value End Set End Property Private _phone As String Public Property Phone() As String Get Return _phone End Get Set(ByVal value As String) _phone = value End Set End Property Private _notes As String Public Property Notes() As String Get Return _notes End Get Set(ByVal value As String) _notes = value End Set End Property Private _bio As String Public Property Bio() As String Get Return _bio End Get Set(ByVal value As String) _bio = value End Set End Property End Class End Module 

If you have an XML file (.xsd), you can import the link to this xmlns into the VB source file, which will give you intellisense to write your LINQ to XML queries.

( Edit: A quick way to create a schema is to open the XML file in Visual Studio and select "Create Schema" in the XML menu.)

For more information and help, please watch the β€œLike Me” video on LINQ by Beth Massi .

+4
source

OK, think about how to do this.

 ... staffBio = staff.Descendants("staffBio").ElementAtOrDefault(0).Value.ToString) ... 

Using .ElementAtOrDefault(0) instead of .Nodes(0) simply returns "" if it is empty or <staffBio>whatever</staffBio> if it is not.

.Value simply returns the contents of anyway tags in the example above.

Is it correct? Can anyone see any problems with this?

0
source

Source: https://habr.com/ru/post/1309650/


All Articles