根据值循环和编辑XML子级

时间:2019-03-21 13:26:41

标签: excel xml vba

我有一个界面来循环浏览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 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的过滤,它现在变得没有多大意义,我被困住了。 / p>

有什么技巧可以解决这个问题吗?谢谢。

1 个答案:

答案 0 :(得分:1)

在问题列表中使用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”的节点,那么仅是更改queryNodes列表的情况,如下所示:

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

访问子节点的代码不会改变,只是因为我们对列表进行了不同的过滤。所有更改都包含在我们创建queryNodes列表的方式中。可以从组合框的事件处理程序中调用更新queryNodes的代码,该组合框允许用户选择一种类型。

我们可以将用于打印所有节点值的代码修改为一个子程序,该子程序将打印特定节点的值(如Tim Williams在评论中所建议的那样):

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的变量来跟踪列表中的位置,则界面中的“上一个”按钮应为position = position - 1,而“下一个”按钮应为position = position + 1

因此,一旦用户按下“上一个”或“下一个”,我们将更新position,然后调用printNode queryNodes.Item(position)。总是有可能我们超出了列表的开头或结尾,可以在尝试调用If Not queryNodes.Item(position) Is Nothing之前用printNode进行检查。

对于您的特定情况,您需要一个子项来填充界面中的字段。为此,将printNode重命名为loadNode,而不是打印到“调试”窗口,而是将相关的文本从每个子节点复制到界面的相应字段中。

一个saveNode函数正好相反-将界面中每个字段的值复制到相关子节点的text属性中