Найти элемент XML по их родному брату

Как найти родственного элемента XML с помощью Visual Basic? Допустим, у меня есть:

<Data>
  <Mail>
    <Subject>Welcome!</Subject>
    <From>Antonios</From>
    <Content>Welcome! How can I assist you?</Content>
  </Mail>
  <Mail>
    <Subject>Test!</Subject>
    <From>John</From>
    <Content>Hello Friend!</Content>
  </Mail>
</Data>

Теперь у меня есть поле со списком, в которое добавляются все темы, поэтому в списке отображаются: Добро пожаловать! и Тест! Теперь я хочу этого, когда нажимаю "Добро пожаловать! ", текстовое поле показывает содержимое элемента "От" сообщения "Добро пожаловать!", а другое текстовое поле показывает "Содержание"< /strong> элемент "Добро пожаловать". Другими словами, я ищу родственный элемент определенного элемента.


person Antonios    schedule 14.08.2012    source источник


Ответы (1)


Вы можете сделать это несколькими способами. Вот как это можно сделать с помощью XmlDocument и XPath:

Dim doc As New XmlDocument()
Dim From As String = doc.SelectSingleNode("/Data/Mail[Subject='Welcome!']/From").InnerText
Dim Content As String = doc.SelectSingleNode("/Data/Mail[Subject='Welcome!']/Content").InnerText

Очевидно, что поскольку тема может быть неуникальной, лучше использовать какой-то элемент, который является уникальным идентификатором, или можно было бы сделать это по индексу. Например, это выбирает из первого почтового сообщения:

Dim From As String = doc.SelectSingleNode("/Data/Mail[1]/From").InnerText

Однако лучший способ сделать что-то подобное — заранее загрузить все необходимые данные в память. Если объем данных не слишком велик, что не похоже на правду, это обычно имеет наибольший смысл. Так, например, я бы рекомендовал создать объект данных, представляющий почтовое сообщение, например:

Public Class Mail
    Public Property Subject() As String
        Get
            Return _subject
        End Get
        Set(ByVal value As String)
            _subject = value
        End Set
    End Property
    Private _subject As String

    Public Property From() As String
        Get
            Return _from
        End Get
        Set(ByVal value As String)
            _from = value
        End Set
    End Property
    Private _from As String

    Public Property Content() As String
        Get
            Return _content
        End Get
        Set(ByVal value As String)
            _content = value
        End Set
    End Property
    Private _content As String

    Public Overrides Function ToString() As String
        Return _subject
    End Function
End Class

Затем вы можете загрузить один объект Mail для каждого элемента Mail в XML. Поскольку метод ToString переопределен для отображения темы, вы можете просто добавить объекты непосредственно в список, например:

Dim doc As New XmlDocument()
For Each node As XmlNode In doc.SelectNodes("/Data/Mail")
    Dim mail As New Mail()
    mail.Subject = node.SelectSingleNode("Subject").InnerText
    mail.From = node.SelectSingleNode("From").InnerText
    mail.Content = node.SelectSingleNode("Content").InnerText
    ListBox1.Items.Add(mail)
Next

Затем, когда элемент в списке выбран, вы можете привести выбранный элемент к типу Mail и получить доступ к его свойствам, например:

Dim mail As Mail = CType(ListBox1.SelectedItem, Mail)
Label1.Text = mail.From
Label2.Text = mail.Content

Однако в этот момент, если данные не слишком велики, еще проще просто использовать XmlSerializer для простой десериализации XML в объект, например, начните с создания класса, который определяет весь XML-документ, например:

Public Class Data
    <XmlElement("Mail")> _
    Public Property Mails() As List(Of Mail)
        Get
            Return _mails
        End Get
        Set(ByVal value As List(Of Mail))
            _mails = value
        End Set
    End Property
    Private _mails As List(Of Mail)
End Class

Затем загрузите XML в окно списка, подобное этому (где xml — это строка, содержащая XML-документ):

Dim serializer As New XmlSerializer(GetType(Data))
Dim reader As New StringReader(xml)
Dim data As Data = CType(serializer.Deserialize(reader), Data)
ListBox1.Items.AddRange(data.Mails.ToArray())

Или, если вы хотите читать из XML-файла напрямую, а не десериализовать его из строки:

Dim serializer As New XmlSerializer(GetType(Data))
Using stream As New FileStream("Test.xml", FileMode.Open)
    Dim data As Data = CType(serializer.Deserialize(stream), Data)
    ListBox1.Items.AddRange(data.Mails.ToArray())
End Using

Чтобы ответить на ваш второй вопрос, который вы задали в своем комментарии ниже, чтобы удалить данное почтовое сообщение, вы можете сделать это следующим образом:

Dim node As XmlNode = doc.SelectSingleNode("/Data/Mail[Subject='Welcome!']")
node.ParentNode.RemoveChild(node)
person Steven Doggart    schedule 14.08.2012
comment
СПАСИБО! Именно то, что я искал! Вы также знаете (так что мне не нужно создавать новую публикацию), как мне удалить определенного родителя ‹Mail› с дочерним элементом ‹Subject›? - person Antonios; 14.08.2012
comment
@Antonios Антониос Я обновил свой ответ, чтобы также ответить на ваш второй вопрос. В будущем, однако, лучше задавать каждый вопрос отдельно. Это более полезно для других людей, которые в будущем будут искать ответ на тот же вопрос, и поможет вам получить больше репутации в придачу. - person Steven Doggart; 14.08.2012