![Office VBA开发经典:中级进阶卷](https://wfqqreader-1252317822.image.myqcloud.com/cover/711/26542711/b_26542711.jpg)
4.6 定位节点
其实,学习XML的DOM对象模型,就是为了更方便地对节点进行定位、读取和修改等操作。由于XML是一个树状结构,节点之间有的是并列关系,有的是所属关系,准确定位到某一节点,通常有很多种方法。以下介绍常用的定位方法。
4.6.1 使用ChildNodes定位所有子节点
XML文件中的一个节点所包含的子节点用ChildNodes集合对象表示。xx.ChildeNodes(0)就表示xx节点的首个子节点。
仍然以“西南省份.xml”为例,该文档对象直属子节点有3个,即处理指令节点、注释节点和根元素节点。XML代码如下。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/079.jpg?sign=1738789793-7KihDqXUm9COhepvNZgQ8AobrP8iZFsm-0-28d644549a7f664ffd186af535ede45b)
下面的过程遍历文档对象的所有子节点(只包括直属子节点,不包括孙节点等)。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/080.jpg?sign=1738789793-N1gKVsSkOo2eQGlidrLdFWygx9EAWrOd-0-bdfa69d40e2eb0427d162a5644b92410)
代码分析:由于各个子节点的类型不一样,因此代码中的对象变量ND需要声明为通用类型.IXMLDOMNode,而不能是IXMLDOMElement。
运行上述过程,在立即窗口打印各子节点的名称、类型和值,如图4-9所示。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/078.jpg?sign=1738789793-2g6QhEMwBV4bRreyMYt6P1duJn0YmZwt-0-c2af90e61357b11e1624b84272c847e5)
图4-9 遍历子节点
需要注意的是,在VBA中DOM对象模型的集合都是以0作为第一个子成员的下标。此外,节点下面的FirstChild也可以定位到第一个子节点,它等价于ChildNodes(0),相对应地,LastChild可以定位到最后一个子节点。
4.6.2 使用PreviousSibling和NextSibling定位前后节点
PreviousSibling与NextSibling表示与节点并列的其他节点,分别表示前一个节点和后一个节点。
“西南省份.xml”中的根元素节点是<Country>,该节点下面包含4个子节点,分别是注释节点和3个元素节点。下列过程用于获取兄弟节点。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/082.jpg?sign=1738789793-GJyPx4cq7dApsq6SQ9gOQIrWx3vqUJFF-0-4f835ff08c13d02915267dac0b82aa2e)
代码分析:本例中ND()是一个数组,分别表示3个Province,由于这3个都是元素节点,因此数组的类型可以声明为具体的IXMLDOMElement。
上述程序的运行结果如图4-10所示。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/081.jpg?sign=1738789793-jIgLKl0g5fmpE97jwOqz3CDkV1hggwae-0-a6e14a5e6e4f72b789b68a4555355d91)
图4-10 获取兄弟节点
4.6.3 使用ParentNode定位父节点
与ChildNodes对应的是ParentNode,ParentNode是指当前节点的上一级节点。由于任一节点的父节点只能是一个,所以该单词后面没有s。
仍然以“西南省份.xml”为例。
在下面的过程中,首先定位到根元素下面的第0个子节点,这是一个注释节点。然后以注释节点为基准,依次回溯其上级节点。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/083.jpg?sign=1738789793-UK0UTPfYAwfwrOWgiiXGaxRg0mGVYvYH-0-a47e2715423848895b55339fed2202b4)
代码分析:ND是一个注释节点,其上级是根元素节点Country,再上一级就是文档对象。
运行上述过程,打印结果如下。
#comment Country #document
注意 如果从XML中的任一节点直接获取根元素节点(祖先节点),可以使用ownerDocument,不需要反复使用ParentNode。
4.6.4 使用XPath定位到任一节点
虽然在实际编程中经常使用ChildNodes定位子节点,但是如果一个XML的嵌套层数非常多,需要多次用到ChildNodes,这时定位就显得麻烦了。
下面介绍使用XPath指定一个路径,从指定节点一步到达定位的深层节点。常用的节点定位的XPath写法如表4-3所示。
表4-3 XPath常用表示形式及其含义
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/887.jpg?sign=1738789793-btmFgwFX6e4VsHbN8gYjQpghtMiuny4K-0-92f3ee39c5d07972ce79167c1230d413)
更多XPath的高级用法,请参阅其他资料。
1. 使用SelectSingleNode获取第一个符合路径的节点
下面的过程使用绝对路径的方式查找到第一个名称为Capital的元素节点。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/084.jpg?sign=1738789793-TBa6aoqtPz3dg4rJJEpgvupQQmtxluRP-0-2d4135c3026b08a997856a9676b64df4)
代码分析:/Country/Province/Capital是一个XPath,表示从根元素开始,逐级定位,一直查到Capital为止。虽然本例中的XML文件中有3个Capital节点,但是程序中用的是SelectSingleNode方法,因此找到第一个即可。
运行上述过程,打印结果如下。
<Capital name="成都"></Capital>
2. 使用SelectNodes获取所有符合路径的节点集合
SelectNodes方法返回的是多个节点构成的集合,因此需要声明为IXMLDOMNodeList类型。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/085.jpg?sign=1738789793-sjkTWjGi2u3bPoDFxJzIyAO5q8zzzYqT-0-0bba7313eac1bb993a926458a2474573)
代码分析:对象变量NL获取了多个符合该路径的节点,因此还需要用For循环遍历每个子节点的信息。
运行上述过程,打印结果如下。
<Capital name="成都"></Capital> <Capital name="贵阳"></Capital> <Capital name="昆明"></Capital>
4.6.5 使用getElementsByTagName定位到一组元素节点
getElementsByTagName方法是以当前节点为基准,查找指定名称的所有元素节点。
下面的过程从文档对象开始查找所有Population元素节点。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/086.jpg?sign=1738789793-D0akBCqJgn8jJ2TpsvN1E69CtJGXCgGj-0-b1dd3c4161fae4335302628bdfcdaadf)
代码分析:这个实例的功能等价于XPath中的//Population。
运行上述过程,打印结果如下。
<Population Unit="万人">8204</Population> <Population Unit="万人">3530</Population> <Population Unit="万人">4742</Population>
4.6.6 使用getAttributeNode定位到属性
元素节点的getAttributeNode方法可以定位到元素中的某一属性,返回一个属性节点。
![](https://epubservercos.yuewen.com/F986E7/15056702504171006/epubprivate/OEBPS/Images/087.jpg?sign=1738789793-jrEjXCaZxP3r14dRPaK4lCq1XPcZSlXq-0-3ecb86fb5d74d2d641630f67a1eb0367)
代码分析:代码中的Root是根元素节点(Country),对象变量A是一个属性节点,表示Country元素的name属性。
运行上述过程,打印结果如下。
name 中国 2
注意 属性一般书写在元素节点的开始标签,但是每一个属性并非元素节点的子节点,因此元素与属性之间的关系不能通过ChildNodes或者ParentNode来描述。
以上内容的源代码文件为“实例文档12.xlsm”。