' [out] firstName: Загруженное имя пользователя
' [out] lastName: Загруженная фамилия пользователя
'--------------------------------------------------------------
Public Shared Sub XML_LoadUserInfo(ByVal fileName As String, _
ByRef userId As Integer, ByRef firstName As String, _
ByRef lastName As String)
Dim currentReadLocation As ReadLocation
'Начинаем с нулевых значении
userId = 0
firstName = ""
lastName = ""
Dim xmlReader As System.Xml.XmlTextReader = _
New System.Xml.XmlTextReader(fileName)
xmlReader.WhitespaceHandling = _
System.Xml.WhitespaceHandling.None
Dim readSuccess As Boolean
readSuccess = xmlReader.Read()
If (readSuccess = False) Then
Throw New System.Exception("Отсутствуют XML-данные для чтения!")
End If
'Убедиться в том, что мы распознали корневой дескриптор
If (xmlReader.Name <> XML_ROOT_TAG) Then
Throw New System.Exception( _
"Корневой дескриптор отличается от ожидаемого!")
End If
'Отметить текущее местоположение в документе
currentReadLocation = ReadLocation.inAllMyData
'------------------------------------------------------
'Цикл прохождения документа и чтение необходимых данных
'------------------------------------------------------
While (readSuccess)
Select Case (xmlReader.NodeType)
'Вызывается при входе в новый элемент
Case System.Xml.XmlNodeType.Element
Dim nodeName As String = xmlReader.Name
LoadHelper_NewElementEncountered(nodeName, _
currentReadLocation)
'--------------------------------------------------
'Здесь мы можем извлечь некоторый фактический текст
'и получить данные, которые пытаемся загрузить
'--------------------------------------------------
Case System.Xml.XmlNodeType.Text
Select Case currentReadLocation
Case ReadLocation.inFirstName
firstName = xmlReader.Value
Case ReadLocation.inLastName
lastName = xmlReader.Value
Case ReadLocation.inUserID
userId = CInt(xmlReader.Value)
End Select
'Конец оператора Case "System.Xml.XmlNodeType.Text"
'----------------------------------------------------
'Вызывается, когда встречается конец
'элемента
'
'Мы можем захотеть переключить состояние в зависимости
'от вида покидаемого узла, чтобы указать на то, что
'собираемся вернуться назад к его предку
'-----------------------------------------------------
Case System.Xml.XmlNodeType.EndElement
Dim continueParsing As Boolean
continueParsing = LoadHelper_EndElementEncountered( _
currentReadLocation)
If (continueParsing = False) Then
GoTo finished_reading_wanted_data
End If
Case Else
'He страшно, если имеются XML-узлы других типов, но
'в нашем примере работы с XML-документом мы должны
'оповестить об этом факте
MsgBox( _
"Встретился непредвиденный XML-тип " + xmlReader.Name)
End Select 'Конец оператора Case, используемого для определения текущего
'типа XML-элeмeнтa, oбpaбaтывaeмoгo анализатором
'Перейти к следующему узлу
readSuccess = xmlReader.Read()
End While
'Если мы оказались в этом месте программы, не покинув
'XML-дескриптора UserInfo, то с XML-данными, которые мы считываем,
'что-то не так
Throw New Exception("He найден элемент UserInfo в XML-документе!")
finished reading_wanted_data:
'Закрыть файл, поскольку работа с ним закончена!
xmlReader.Close()
End Sub
'--------------------------------------------------------
'Вспомогательный код, ответственный за принятие решения
'относительно того, в какое состояние необходимо перейти,
'когда встречается закрывающий дескриптор
'--------------------------------------------------------
Private Shared Function LoadHelper_EndElementEncountered( _
ByRef currentReadLocation As ReadLocation) As Boolean
Select Case (currentReadLocation)
'Если мы покидаем узел Name, то должны вернуться
'обратно в узел UserInfo
Case ReadLocation.inName
currentReadLocation = ReadLocation.inUserInfo
'Если мы покидаем узел FirstName, то должны вернуться
'обратно в узел Name
Case ReadLocation.inFirstName
currentReadLocation = ReadLocation.inName
'Если мы покидаем узел LastName, то должны вернуться
'обратно в узел Name
Case ReadLocation.inLastName
currentReadLocation = ReadLocation.inName
'Если мы покидаем узел UserID, то должны вернуться
'обратно в узел UserInfo
Case ReadLocation.inUserID
currentReadLocation = ReadLocation.inUserInfo
'Если мы покидаем узел UserInfo, то мы только что
'закончили чтение данных в узлах UserID, FirstName
'и LastName
'
'Можно выйти из цикла, поскольку у нас уже есть вся
'информация, которую мы хотели получить!
Case ReadLocation.inUserInfo
Return False 'Анализ должен быть прекращен
End Select
Return True
'Продолжить анализ
End Function
Private Shared Sub LoadHelper_NewElementEncountered( _
ByVal nodeName As String, _
ByRef currentReadLocation As ReadLocation)
'----------------------------------------------------
'Мы вошли в новый элемент!
'В какое состояние переход возможен, зависит от того,
'в каком состоянии мы находимся в данный момент
'----------------------------------------------------
Select Case (currentReadLocation)
'Если мы находимся в узле AllMyData, то переход возможен
'в узлы, которые указаны ниже
Case (ReadLocation.inAllMyData)
If (nodeName = XML_USERINFO_TAG) Then
currentReadLocation = ReadLocation.inUserInfo
End If
'Если мы находимся в узле UserInfo, то переход возможен
'в узлы, которые указаны ниже
Case (ReadLocation.inUserInfo)
If (nodeName = XML_USERID_TAG) Then
currentReadLocation = ReadLocation.inUserID
ElseIf (nodeName = XML_NAMEINFO_TAG) Then
currentReadLocation = ReadLocation.inName
End If
'Если мы находимся в узле Name, то переход возможен
'в узлы, которые указаны ниже
Case (ReadLocation.inName)
If (nodeName = XML_FIRSTNAME_TAG) Then
currentReadLocation = ReadLocation.inFirstName
ElseIf (nodeName = XML LASTNAME_TAG) Then
currentReadLocation = ReadLocation.inLastName
End If
End Select
End Sub
End Class
Примеры к главе 11 (производительность и графика)
Листинг 11.1. Заполнение данными и очистка от них элементов управления TreeView с использованием альтернативных стратегий
'----------------------------------------------------------------------------
'Примечание #1: В этом примере используется класс PerformanceSampling,
' определённый ранее в данной книге. Убедитесь в том, что
' вы включили этот класс в свой проект.
'Примечание #2: Этот код необходимо включить в класс Form, содержащий элемент
' управления TreeView и кнопки Button, к которым подключены
' приведенные ниже функции xxx_Click.
'----------------------------------------------------------------------------
'Количество элементов, которые необходимо поместить в элемент
'управления TreeView
Const NUMBER_ITEMS As Integer = 800
'-------------------------------------------------------------------------
'Код для кнопки "Fill: Baseline"
'Использование неоптимизированного подхода для заполнения данными элемента
'управления TreeView
'-------------------------------------------------------------------------
Private Sub UnOptimizedFill_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles UnOptimizedFill.Click
'Очистить массив для создания одинаковых условий тестирования
If (TreeView1.Nodes.Count > 0) Then
TreeView1.BeginUpdate()
TreeView1.Nodes.Clear()
TreeView1.EndUpdate()
TreeView1.Update()
End If
'Для повышения корректности тестирования предварительно выполнить
'операцию сборки мусора. В реальных кодах этого делать не следует!
System.GC.Collect()
'Запустить таймер
PerformanceSampling.StartSample(0, "TreeViewPopulate")
'Заполнить данными элемент управления TreeView
Dim i As Integer
For i = 1 To NUMBER_ITEMS
TreeView1.Nodes.Add("TreeItem" + CStr(i))
Next
'Остановить таймер и отобразить результат
PerformanceSampling.StopSample(0)
MsgBox(PerformanceSampling.GetSampleDurationText(0))
End Sub