动易SW中的一个严重但不影响使用的bug(二)

  上次分析出来了Bug的问题所在,是因为selectSingleNode(strNodeName)不能取到要取的元素,但是为什么这么大的Bug没有出现500错误呢?否则的话,这么大的一个bug不要说是来到用户手上,在开发人员手里就已经被发现了。

  这次继续分析这个Bug。在新版本的API_Function.asp这个文件中,selectSingleNode这个函数一共用到了5次,有两次是在SendPost函数里,在很早的版本里那两个地方就用的是selectSingleNode,因为那里传递的参数用的是“//status”和“//message”,是正确的XPath,因此不用考虑那里了。此外的三处,代码如下:

'**************************************************
'函数名:getNodeText
'作  用:获取XML文件中指定节点的文本
'参  数:strNodeName   ----节点名称
'返回值:解析出来的文本值,
'**************************************************
Function getNodeText(strNodeName)
    If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = "" Then Exit Function
    If IsNode(strNodeName) Then
        getNodeText = sMyXmlDoc.documentElement.selectSingleNode(strNodeName).Text
    Else
        getNodeText = ""
    End If
End Function  

'**************************************************
'函数名:setNodeText
'作  用:设置XML文件中指定节点的文本
'参  数:strNodeName   ----节点名称
'    strNodeText   ----要设置的文本
'返回值:0 = 设置成功; 否则返回Err.Description
'**************************************************
Function setNodeText(strNodeName, strNodeText)
    If IsNull(strNodeText) Or IsEmpty(strNodeText) Or strNodeText = "" Then Exit Function
    If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = "" Then Exit Function
    If IsNode(strNodeName) Then sMyXmlDoc.documentElement.selectSingleNode(strNodeName).Text = strNodeText
End Function  

'**************************************************
'函数名:IsNode
'作  用:检查一个Node是否存在且文本不为空
'参  数:strNodeName   ----节点名称
'返回值:True or False
'**************************************************
Function IsNode(strNodeName)
    IsNode = False
    If strNodeName = "" Then Exit Function
    If sMyXmlDoc.documentElement.selectSingleNode(strNodeName) Is Nothing Then
        IsNode = False
    Else
        IsNode = True
    End If
End Function

  我们来看,为什么设置message的值不会成功并且不报错呢?原因就在于setNodeText这个函数的最后一句:

ASP/Visual Basic代码
  1. If IsNode(strNodeName) Then sMyXmlDoc.documentElement.selectSingleNode(strNodeName).Text = strNodeText

  IsNode这个函数,从函数的注释(还好这个没改)可以看出,作用是“检测一个元素是否存在且文本不为空”,这个函数本来的作用是用于检查传递的数据包中的“自定义元素”和“扩展元素”的,因为各个接口对标准的支持程度不同,因此在获取数据的时候,有的元素可能只是穿了空值过来,那我们就没有必要对该元素进行处理了,所以要用IsNode来检查一下。但是在setNodeText这个函数里没有调用过IsNode检查。就算调用了,按照以前的方式,一定会取到“message”元素的默认值,从而返回True。

  在新版本中,由于采用了selectSingleNode来取“message”已经取不到了,自然,IsNode这个函数在检查到message的时候,必然返回空值,因为 sMyXmlDoc.documentElement.selectSingleNode Is Nothing这个判断为真了,所以会返回False。于是,sMyXmlDoc.documentElement.selectSingleNode(“message”).Text 这个语句就不会执行,也就不会引发500错误了。

  做个假设,如果在修改了取元素的方式之后,没有给setNodeText和getNodeText加上IsNode判断,则必然引发500错误。或者,没有修改过IsNode这个函数,则仍然会返回True,然后引发500错误。正好是加上了判断,于是所有对message元素的值的读写都被忽略了,默认值“操作已成功”就这样被原封不动地回发给所有请求,而响应包中的用户数据元素也一样。

  下面是纠正bug的代码:

ASP/Visual Basic代码
  1. ‘**************************************************
  2. ‘函数名:getNodeText
  3. ‘作 用:获取XML文件中指定节点的文本
  4. ‘参 数:strNodeName —-节点名称
  5. ‘返回值:解析出来的文本值,
  6. ‘**************************************************
  7. Function getNodeText(strNodeName)
  8. If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = “” Then Exit Function
  9. If IsNode(strNodeName) Then
  10. getNodeText = sMyXmlDoc.documentElement.getElementsByTagName(strNodeName).Item(0).Text
  11. Else
  12. getNodeText = “”
  13. End If
  14. End Function
  15. ‘**************************************************
  16. ‘函数名:setNodeText
  17. ‘作 用:设置XML文件中指定节点的文本
  18. ‘参 数:strNodeName —-节点名称
  19. ‘    strNodeText —-要设置的文本
  20. ‘返回值:0 = 设置成功; 否则返回Err.Description
  21. ‘**************************************************
  22. Function setNodeText(strNodeName, strNodeText)
  23. If IsNull(strNodeText) Or IsEmpty(strNodeText) Or strNodeText = “” Then Exit Function
  24. If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = “” Then Exit Function
  25. If IsNode(strNodeName) Then sMyXmlDoc.documentElement.getElementsByTagName(strNodeName).Item(0).Text = strNodeText
  26. End Function
  27. ‘**************************************************
  28. ‘函数名:IsNode
  29. ‘作 用:检查一个Node是否存在且文本不为空
  30. ‘参 数:strNodeName —-节点名称
  31. ‘返回值:True or False
  32. ‘**************************************************
  33. Function IsNode(strNodeName)
  34. IsNode = False
  35. If strNodeName = “” Then Exit Function
  36. If sMyXmlDoc.documentElement.getElementsByTagName(strNodeName).Item(0) Is Nothing Or IsEmpty(sMyXmlDoc.documentElement.getElementByTagName(strNodeName).Item(0).Text) Then
  37. IsNode = False
  38. Else
  39. IsNode = True
  40. End If
  41. End Function

第二种改法:用selectSingleNode的方法,代码如下

ASP/Visual Basic代码
  1. ‘**************************************************
  2. ‘函数名:getNodeText
  3. ‘作 用:获取XML文件中指定节点的文本
  4. ‘参 数:strNodeName —-节点名称
  5. ‘返回值:解析出来的文本值,
  6. ‘**************************************************
  7. Function getNodeText(strNodeName)
  8. If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = “” Then Exit Function
  9. If IsNode(strNodeName) Then
  10. getNodeText = sMyXmlDoc.documentElement.selectSingleNode(“//”&strNodeName).Text
  11. Else
  12. getNodeText = “”
  13. End If
  14. End Function
  15. ‘**************************************************
  16. ‘函数名:setNodeText
  17. ‘作 用:设置XML文件中指定节点的文本
  18. ‘参 数:strNodeName —-节点名称
  19. ‘    strNodeText —-要设置的文本
  20. ‘返回值:0 = 设置成功; 否则返回Err.Description
  21. ‘**************************************************
  22. Function setNodeText(strNodeName, strNodeText)
  23. If IsNull(strNodeText) Or IsEmpty(strNodeText) Or strNodeText = “” Then Exit Function
  24. If IsNull(strNodeName) Or IsEmpty(strNodeName) Or strNodeName = “” Then Exit Function
  25. If IsNode(strNodeName) Then sMyXmlDoc.documentElement.selectSingleNode(“//”&strNodeName).Text = strNodeText
  26. End Function
  27. ‘**************************************************
  28. ‘函数名:IsNode
  29. ‘作 用:检查一个Node是否存在且文本不为空
  30. ‘参 数:strNodeName —-节点名称
  31. ‘返回值:True or False
  32. ‘**************************************************
  33. Function IsNode(strNodeName)
  34. IsNode = False
  35. If strNodeName = “” Then Exit Function
  36. If sMyXmlDoc.documentElement.selectSingleNode(“//”&strNodeName) Is Nothing Or IsEmpty(sMyXmlDoc.documentElement.selectSingleNode(“//”&strNodeName).Text) Then
  37. IsNode = False
  38. Else
  39. IsNode = True
  40. End If
  41. End Function

  这样就能充分利用selectSingleNode的简洁了,但是还要注意哦,由于新版本的createXmlDom不再是自动生成支持的最高版本的xmldom对象,而是生成默认版本(系统默认版本一般都是3.0以下),而低于4.0的版本中,selectSingleNode对XPath的支持是有问题的,不支持带函数的XPath,所以还要小心!