人们......这是我最近提出的类似问题的后续跟进。如何从XML结构中检索特定值,而无需沿着结构向下移动并遍历所有子节点?有人建议我应该使用XPath。
假设以下简化的XML结构:
<MyWeather>
<sensor location="Front Entry">
<reading label="Temperature">
<title>Front Entry</title>
<label>Temperature</label>
<value>54</value>
<units>F</units>
<lastUpdate>05/27/2013 12:23 AM</lastUpdate>
</reading>
<reading label="Humidity">
<title>Front Entry</title>
<label>Humidity</label>
<value>66</value>
<units>%</units>
<lastUpdate>05/27/2013 12:23 AM</lastUpdate>
</reading>
</sensor>
<sensor location="Patio">
<reading label="Temperature">
<title>Patio</title>
<label>Temperature</label>
<value>46</value>
<units>F</units>
<lastUpdate>05/27/2013 12:23 AM</lastUpdate>
</reading>
<reading label="Humidity">
<title>Patio</title>
<label>Humidity</label>
<value>93</value>
<units>%</units>
<lastUpdate>05/27/2013 12:23 AM</lastUpdate>
</reading>
</sensor>
</MyWeather>
以下是我的ASP页面的一部分:
<%
xmlDoc = CreateObject("Msxml2.DOMDocument")
xmldoc.setProperty ("ServerHTTPRequest", true)
xmlDoc.setProperty ("ProhibitDTD", False)
xmlDoc.validateOnParse = true
' Filename is a sting variable containing the URL
xmlDoc.async = "False"
xmlDoc.load(FileName)
' Error and return code processing done here but removed
For Each el In xmldoc.childNodes
if el.childnodes.length <> 0 then
response.write ("<table align='center' class='auto-style1'>")
for each el2 in el.childnodes
Response.write("<tr><td>" & el2.getattribute("location") & "</td><td></td></tr>")
for each el3 in el2.childnodes
for each el4 in el3.childnodes
if el4.nodename = "value" then
Response.write("<tr><td></td><td>" & el3.getattribute("label") & " " & el4.text & " " & el4.nextSibling.text & "</td></tr>")
exit for
end if
next
next
next
response.write ("</table>")
end if
Next
xmlDoc = Nothing
%>
我的问题与“对于每个el4 in ... ”部分中的代码有关。你看到我遍历子节点,直到找到“值”。然后我输出那个标签值,并且,因为我知道下一个标签(现在直到他们改变它),是“units”标签我使用nextsibling来获得该值。 此代码有效!
我想知道的是: 在没有迭代过程的情况下,对于传感器位置和读取标签的任意组合,是否有更直接的方法来实现这两个标记值。
我还有其他一些案例,我可能需要遍历50多个元素才能找到我正在寻找的标签。
我根据上一个问题的建议添加了此xPath代码。这个,如果有效,将替换上面的“el3.childnodes循环中的每个el4的”
xmlDoc.setProperty ("SelectionLanguage", "XPath")
oNode = xmldoc.selectSingleNode("//reading[@label='Temperaure']/units")
o2Node = xmldoc.selectSingleNode("//reading[@label='Temperaure']/value")
if oNode is nothing or o2node is nothing then
Response.write("<tr><td></td><td> Nothing found for value or units </td><td>" & el3.getattribute("label") & "</tr>")
else
Response.write("<tr><td></td><td>" & el3.getattribute("label") & " " & o2Node.text & " " & oNode.text & "</td></tr>")
end if
然而,它对我不起作用。我尝试了几种变体:没有@符号和oNode语句中的完整路径,即/ MyWeather / sensor / reading /...
我对空oNode和/或O2Node的检查始终为真。
任何想法?...... RDK
答案 0 :(得分:0)
如果您已经遍历了所有嵌套For Each
循环的树,那么要替换另一个嵌套For Each
,您需要确保在变量上调用selectSingleNode
外For Each
并使用相对路径,例如
Response.Write el3.selectSingleNode("value").text
我强烈建议不要使用childNodes,只是为了确保你使用selectNodes
和你感兴趣的元素的路径,这样你正在处理的元素节点就更清楚了;例如,如果您确实检查了XML输入是否已成功解析并进行错误检查,那么
For Each el In xmldoc.childNodes
if el.childnodes.length <> 0 then
response.write ("<table align='center' class='auto-style1'>")
是多余的,因为格式良好的XML文档总是有一个根元素子节点,所以一旦你检查了,例如
If xmlDoc.parseError.errorCode = 0 Then
Response.Write ("<table align='center' class='auto-style1'>")
应该足够了。
如果您想要访问根元素(在您的情况下是MyWheater
元素),则只需使用xmlDoc.documentElement
。
此外,您可以使用
For Each sensor In xmlDoc.documentElement.selectNodes("sensor")
Dim tr
Set tr = sensor.selectSingleNode("reading[@label = 'Temperature']")
Response.Write tr.selectSingleNode("value").text & " " & tr.selectSingleNode("unit").text
Next
唯一的XML问题是命名空间,如果您的真实XML具有xmlns="http://example.com"
之类的属性,或者您有任何DTD将这些属性设置为默认值,那么您需要使用MSXML。
xmlDoc.setProperty "SelectionNamespaces", "xmlns:df='http://example.com'"
并且还需要使用该前缀(例如df
)来限定传递给selectNodes
和selectSingleNode
的XPath表达式中的元素名称,即
For Each sensor In xmlDoc.documentElement.selectNodes("df:sensor")
Dim tr
Set tr = sensor.selectSingleNode("df:reading[@label = 'Temperature']")
Response.Write tr.selectSingleNode("df:value").text & " " & tr.selectSingleNode("df:unit").text
Next