代码之家  ›  专栏  ›  技术社区  ›  JasonPlutext

XPath在VBA中返回字符串或布尔值?

  •  2
  • JasonPlutext  · 技术社区  · 14 年前

    Word宏执行XPath表达式的最简单方法是什么,例如:

    "string(/alpha/beta)" 
    
    "not(string(/alpha/beta)='true')" 
    

    哪个应该分别返回字符串和布尔值?(与xml节点或节点列表相反)

    函数selectSingleNode(queryString As String)返回一个IXMLDOMNode,这样就不会了。

    换句话说,类似于.NET的xpathnavigator.evaluate[1]的东西,这是什么?

    [一] http://msdn.microsoft.com/en-us/library/2c16b7x8.aspx

    1 回复  |  直到 14 年前
        1
  •  3
  •   Community Neeleshkumar S    7 年前

    可以使用XSL转换计算XPath表达式,特别是 xsl:value-of .

    我写了一篇 Evaluate 在这个原则上起作用的函数。它在内存中创建一个XSL样式表,其中包含一个XSL模板,该模板将接受一个XPath表达式,对其求值,并返回一个新的XML文档,该文档包含 <result> 节点。它会检查以确保 value-of Long , Double Boolean ,或 String .

    books.xml 链接到的MSDN页中的文件(必须将路径更改为 books.xml文件 如果你想运行这些测试)。

    Public Sub Test_Evaluate()
    
        Dim doc As New DOMDocument
        Dim value As Variant
    
        doc.async = False
        doc.Load "C:\Development\StackOverflow\XPath Evaluation\books.xml"
    
        Debug.Assert (doc.parseError.errorCode = 0)
    
        ' Sum of book prices should be a Double and equal to 30.97
        '
        value = Evaluate(doc, "sum(descendant::price)")
        Debug.Assert TypeName(value) = "Double"
        Debug.Assert value = 30.97
    
        ' Title of second book using text() selector should be "The Confidence Man"
        '
        value = Evaluate(doc, "descendant::book[2]/title/text()")
        Debug.Assert TypeName(value) = "String"
        Debug.Assert value = "The Confidence Man"
    
        ' Title of second book using string() function should be "The Confidence Man"
        '
        value = Evaluate(doc, "string(/bookstore/book[2]/title)")
        Debug.Assert TypeName(value) = "String"
        Debug.Assert value = "The Confidence Man"
    
        ' Total number of books should be 3
        '
        value = Evaluate(doc, "count(descendant::book)")
        Debug.Assert TypeName(value) = "Long"
        Debug.Assert value = 3
    
        ' Title of first book should not be "The Great Gatsby"
        '
        value = Evaluate(doc, "not(string(/bookstore/book[1]/title))='The Great Gatsby'")
        Debug.Assert TypeName(value) = "Boolean"
        Debug.Assert value = False
    
        ' Genre of second book should be "novel"
        '
        value = Evaluate(doc, "string(/bookstore/book[2]/attribute::genre)='novel'")
        Debug.Assert TypeName(value) = "Boolean"
        Debug.Assert value = True
    
        ' Selecting a non-existent node should generate an error
        '
        On Error Resume Next
    
        value = Evaluate(doc, "string(/bookstore/paperback[1])")
        Debug.Assert Err.Number = vbObjectError
    
        On Error GoTo 0
    
    End Sub
    

    这里是 评价 IsLong 函数是帮助函数,使数据类型转换代码更具可读性):


    注: 作为 barrowc DOMDocument 具有特定于版本的类名,例如 DOMDocument30 (MSXML3)或 DOMDocument60

    看问题 Which version of MSXML should I use? 有关MSXML不同版本的详细信息。


    Public Function Evaluate(ByVal doc As DOMDocument, ByVal xpath As String) As Variant
    
        Static styleDoc As DOMDocument
        Dim valueOf As IXMLDOMElement
        Dim resultDoc As DOMDocument
        Dim result As Variant
    
        If styleDoc Is Nothing Then
    
            Set styleDoc = New DOMDocument
    
            styleDoc.loadXML _
                "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" & _
                    "<xsl:template match='/'>" & _
                        "<result>" & _
                            "<xsl:value-of />" & _
                        "</result>" & _
                    "</xsl:template>" & _
                "</xsl:stylesheet>"
    
        End If
    
        Set valueOf = styleDoc.selectSingleNode("//xsl:value-of")
        valueOf.setAttribute "select", xpath
    
        Set resultDoc = New DOMDocument
        doc.transformNodeToObject styleDoc, resultDoc
    
        If resultDoc.documentElement.childNodes.length = 0 Then
            Err.Raise vbObjectError, , "Expression '" & xpath & "' returned no results."
        End If
    
        result = resultDoc.documentElement.Text
    
        If IsLong(result) Then
            result = CLng(result)
        ElseIf IsNumeric(result) Then
            result = CDbl(result)
        ElseIf result = "true" Or result = "false" Then
            result = CBool(result)
        End If
    
        Evaluate = result
    
    End Function
    
    Private Function IsLong(ByVal value As Variant) As Boolean
    
        Dim temp As Long
    
        If Not IsNumeric(value) Then
            Exit Function
        End If
    
        On Error Resume Next
    
        temp = CLng(value)
    
        If Not Err.Number Then
            IsLong = (temp = CDbl(value))
        End If
    
    End Function