Цикл и редактирование через XML дочерние элементы на основе значений - PullRequest
1 голос
/ 21 марта 2019

У меня есть интерфейс для циклического перехода через дочерний XML и их редактирования. Примерно так:

XML

Файл XML выглядит так:

 <?xml version="1.0"?>
    <catalog>
       <query id="bk100">
          <question>Do we have Docker security?</question>
          <answer>Yes</answer>
          <comment>None</comment>
          <genre>Cloud</genre>
       </query>
       <query id="bk101">
          <question>Do we have cloud security</question>
          <answer>Yes</answer>
          <comment>None</comment>
          <genre>SCPC</genre>
       </query>
       <query id="bk100">
          <question>Do we have Kubernetos security?</question>
          <answer>Yes</answer>
          <comment>None</comment>
          <genre>Cloud</genre>
       </query>
    </catalog>

Я читаю и храню детей как таковых в Global variabes:

xmlUrl = ThisWorkbook.Path & "\Blah.xml"
oXMLFile.Load (xmlUrl)
Set QuestionNodes = oXMLFile.SelectNodes("/catalog/query/question/text()")

Теперь, когда пользователь выбирает Genre во внутреннем интерфейсе (используя комбинированный список или что-то еще), например, SCPC - я хочу, чтобы кнопки «Следующая» и «Предыдущая» позволяли просто циклически просматривать вопросы и ответы (и редактировать). их) в Genre SCPC

так, например, псевдо-реализация для `` Next button` будет выглядеть так:

'Next XML Node Iterartor
Private Sub btnNextEntry_Click()
   Interate Where GenreNodes(i).NodeValue = "SCPC"
        txtQuestion.Value = QuestionNodes(i).NodeValue
        Pause 'When the user clicks Next again, the Next Node Data Is Showed
End Sub

и аналогично что-то для Previous button. Очевидно, у меня нет логики, как этого добиться. Так как мне также нужно иметь функции редактирования и сохранения, я подумал, что было бы неплохо использовать итерацию на основе индекса, но с фильтрацией на основе Genre это не имеет большого смысла, и я застрял.

Какие-нибудь советы, как мне справиться с этим? Спасибо.

1 Ответ

1 голос
/ 22 марта 2019

Использование Set QuestionNodes = oXMLFile.SelectNodes("/catalog/query/question/text()") для списка вопросов затрудняет фильтрацию, чем это необходимо.Проще использовать список узлов запроса и затем обращаться к дочерним узлам по мере необходимости.

Итак, если вы хотите перечислить все узлы, используйте:

Dim queryNodes As IXMLDOMNodeList
' ...
Set queryNodes = oXmlFile.SelectNodes("/catalog/query")

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

Dim node As IXMLDOMNode

For Each node In queryNodes
    Debug.Print "Q: " & node.SelectSingleNode("question").Text & vbCrLf & _
        "A: " & node.SelectSingleNode("answer").Text & vbCrLf & _
        "C: " & node.SelectSingleNode("comment").Text & vbCrLf & _
        "G: " & node.SelectSingleNode("genre").Text & vbCrLf & vbCrLf
Next node

Если затем вы хотите работать только с узлами, где жанр "SCPC", тогда это просто случай изменения queryNodeslist, например:

Set queryNodes = oXmlFile.SelectNodes("/catalog/query[genre='SCPC']")

Код для доступа к дочерним узлам не меняется только потому, что мы отфильтровали список по-другому.Все изменения содержатся в том, как мы создаем список queryNodes.Код для обновления queryNodes можно вызвать из обработчика событий для выпадающего списка, который позволяет пользователю выбрать жанр.

Мы могли бы адаптировать код для печати всех значений узла в подпрограмму, которая печатаетзначения определенного узла (как это было предложено Тимом Уильямсом в комментариях):

Sub printNode(node As IXMLDOMNode)

Debug.Print "Q: " & node.SelectSingleNode("question").Text & vbCrLf & _
    "A: " & node.SelectSingleNode("answer").Text & vbCrLf & _
    "C: " & node.SelectSingleNode("comment").Text & vbCrLf & _
    "G: " & node.SelectSingleNode("genre").Text & vbCrLf & vbCrLf

End Sub

Чтобы контролировать, какой узел отображается через ваш интерфейс, используйте свойство Item из списка queryNodes.Первый узел - queryNodes.Item(0), следующий - queryNodes.Item(1) и т. Д.

Если мы используем переменную с именем position для отслеживания того, где мы находимся в списке, тогда кнопка Previous в вашем интерфейседолжно составить position = position - 1, а ваша кнопка «Далее» - position = position + 1.

Итак, когда пользователь нажмет «Предыдущий» или «Далее», мы обновим position и затем вызовем printNode queryNodes.Item(position).Всегда есть вероятность того, что мы вышли за пределы начала или конца списка, и это можно проверить с помощью If Not queryNodes.Item(position) Is Nothing, прежде чем мы попытаемся вызвать printNode.

. Для вашего конкретного случая вы бынужна подпрограмма для заполнения полей в вашем интерфейсе.Для этого переименуйте printNode в loadNode и вместо печати в окне отладки скопируйте соответствующий текст из каждого дочернего узла в соответствующее поле в вашем интерфейсе.

Функция saveNode будеттолько наоборот: скопируйте значение каждого поля в вашем интерфейсе в текстовое свойство соответствующего дочернего узла

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