如何使用 Linq 获取 XML 元素的值(即使为空)

发布于 2024-09-01 13:06:06 字数 1669 浏览 3 评论 0原文

请原谅我的愚蠢,我倾向于发现遍历 XML 过于复杂。

我在 VB 中使用 ASP.NET。

我有一个 XML 文档,其中包含我公司员工的所有详细信息...

<staff>
    <staffName>Test Staff</staffName>
    <staffTitle>Slave</staffTitle>
    <staffDepartmentName>Finance</staffDepartmentName>
    <staffOffice>London</staffOffice>
    <staffEmail>[email protected]</staffEmail>
    <staffPhone>0207 123 456</staffPhone>
    <staffNotes>Working hours Mon to Thurs 9.15 - 5.15</staffNotes>
    <staffBio></staffBio>
</staff>

如您所见,某些节点并不总是包含所有员工的数据;只有董事才有传记。

我访问这样的值...

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

一旦到达 StaffBio,我收到一条错误消息“对象引用未设置为对象的实例”。显然是因为该节点不存在。

我的问题是,即使变量为空,如何将值分配给变量,而不必在每次赋值之前进行条件检查?

Please excuse my stupidity, I tend to find the traversing XML overly complicated.

I am using ASP.NET in VB.

I have an XML document which contains all the details of staff in my company...

<staff>
    <staffName>Test Staff</staffName>
    <staffTitle>Slave</staffTitle>
    <staffDepartmentName>Finance</staffDepartmentName>
    <staffOffice>London</staffOffice>
    <staffEmail>[email protected]</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 for ever member of staff; only Directors have biographies.

I access the values like this...

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

Once it gets to staffBio I get an error saying "Object reference not set to an instance of an object." obviously because that node does not exist.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苏佲洛 2024-09-08 13:06:06

首先,myXMLFile.Descendants("staff").Descendants("staffName") 是多余的。 Descendants 返回 XDocumentXElement 内任何级别的所有元素。因此,myXMLFile.Descendants("staffName") 将给出相同的结果。

其次,您可以像这样使用 Element 属性和 Value 属性:

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

staff 将只有一个 staffBio 元素,因此无需使用 Descendants 属性。 Value 是一个字符串,因此您不需要调用Value.ToString。如果元素为空,则 Value 将返回一个空字符串,这就是您要查找的内容!

第三,在 VB.NET 中有一种更好的(而且我认为更直接的)方法可以做到这一点。下面是一个控制台应用程序,演示了我将如何执行此操作:

Module Module1

Sub Main()
    Dim myXMLFile = <allStaff>
                        <staff>
                            <staffName>Test Staff</staffName>
                            <staffTitle>Slave</staffTitle>
                            <staffDepartmentName>Finance</staffDepartmentName>
                            <staffOffice>London</staffOffice>
                            <staffEmail>[email protected]</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>[email protected]</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

如果您有 XML 的架构(.xsd 文件),那么您可以将该 xmlns 的引用导入到 VB 源文件中,这将为您提供用于编写​​ LINQ 的智能感知XML 查询。

编辑:创建架构的快速方法是在 Visual Studio 中打开 XML 文件,然后从 XML 菜单中选择“创建架构”。)

有关详细信息和帮助,请查看 Beth Massi 的有关 LINQ 的“How Do I”视频系列

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

Second, you can just use the Element property and the Value property like this:

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

staff will only have one staffBio element, so there's no need to use the Descendants property. Value is a string, so you don't need to call Value.ToString. If the element is empty, then Value will return an empty string, which is what you're looking for!

Third, there is a much better (and I believe more straight forward) way of doing this in VB.NET. Here's a console app that demonstrates how I would do this:

Module Module1

Sub Main()
    Dim myXMLFile = <allStaff>
                        <staff>
                            <staffName>Test Staff</staffName>
                            <staffTitle>Slave</staffTitle>
                            <staffDepartmentName>Finance</staffDepartmentName>
                            <staffOffice>London</staffOffice>
                            <staffEmail>[email protected]</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>[email protected]</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 a schema (.xsd file) for your XML, then you can import a reference to that xmlns to your VB source file, which will give you intellisense for writing your LINQ to XML queries.

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

For more information and help, please check out the "How Do I" video series on LINQ by Beth Massi.

戒ㄋ 2024-09-08 13:06:06

好吧,想想这是怎么做的。

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

使用 .ElementAtOrDefault(0) 而不是 .Nodes(0) 仅返回“”(如果它为空)或 whatever 如果不是。

.Value 只是返回标签的内容,如上例中的“whatever”。

这是对的吗?任何人都可以看到这有什么问题吗?

OK think this is how to do it.

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

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

.Value just returns the content of the tags like "whatever" in the example above.

Is this right? Can anyone see any problems with this?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文