Как получить значение элемента XML с помощью Linq, даже если он пуст - PullRequest
4 голосов
/ 13 мая 2010

Пожалуйста, извините за мою глупость, мне кажется, что обходной XML слишком сложен.

Я использую ASP.NET в VB.

У меня есть XML-документ, который содержит все данные о персонале в моей компании ...

<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>

Как видите, некоторые узлы не всегда содержат данные о членах персонала; только директора имеют биографии.

Я получаю доступ к таким значениям ...

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, я получаю сообщение об ошибке: «Ссылка на объект не установлена ​​для экземпляра объекта». очевидно, потому что этот узел не существует.

У меня вопрос, как я могу присвоить значение переменной, даже если она пуста, без необходимости выполнять условную проверку перед каждым присваиванием?

Ответы [ 2 ]

4 голосов
/ 13 мая 2010

Во-первых, myXMLFile.Descendants("staff").Descendants("staffName") является избыточным. Потомки возвращают все элементы любого уровня в пределах XDocument или XElement. Таким образом, 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>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

Если у вас есть схема (файл .xsd) для вашего XML, то вы можете импортировать ссылку на этот xmlns в ваш исходный файл VB, что даст вам интеллектуальный смысл для записи запросов LINQ to XML.

( Редактировать: Быстрый способ создания схемы - открыть файл XML в Visual Studio и выбрать Создать схему из меню XML.)

Для получения дополнительной информации и помощи, пожалуйста, ознакомьтесь с видео серией «Как я» на LINQ Бет Масси .

0 голосов
/ 13 мая 2010

ОК, думаю, это как это сделать.

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

Использование .ElementAtOrDefault(0) вместо .Nodes(0) просто возвращает "", если оно пустое, или <staffBio>whatever</staffBio>, если это не так.

.Value просто возвращает содержимое тегов типа «что угодно» в приведенном выше примере.

Это правильно? Кто-нибудь может увидеть какие-либо проблемы с этим?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...