1

伙计们……这是对我最近提出的类似问题的跟进。如何从 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

%>

我的问题与“ For each el4 in ... ”部分中的代码有关。您会看到我遍历子节点,直到找到“价值”。然后我输出那个标签值,并且我知道下一个标签(现在直到他们改变它),是我使用 nextsibling 来获取那个值的“单位”标签。 此代码有效!

我想知道的是:对于传感器位置读取标签的任何组合,是否有更直接的方法来获取这两个标签值,而无需我的迭代过程。

我还有其他几种情况,我可能需要遍历 50 多个元素才能找到我正在寻找的标签。

我根据上一个问题的建议添加了这个 xPath 代码。如果它有效,它将替换上面的“ for each el4 in el3.childnodes loop

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

4

1 回答 1

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和的 XPath 表达式中的元素名称,selectSingleNode

  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
于 2013-06-02T09:19:03.210 回答