How to get xpath from an XmlNode instance

后端 未结 14 1103
难免孤独
难免孤独 2020-11-30 18:17

Could someone supply some code that would get the xpath of a System.Xml.XmlNode instance?

Thanks!

14条回答
  •  鱼传尺愫
    2020-11-30 18:58

    I produced VBA for Excel to do this for a work project. It outputs tuples of an Xpath and the associated text from an elemen or attribute. The purpose was to allow business analysts to identify and map some xml. Appreciate that this is a C# forum, but thought this may be of interest.

    Sub Parse2(oSh As Long, inode As IXMLDOMNode, Optional iXstring As String = "", Optional indexes)
    
    
    Dim chnode As IXMLDOMNode
    Dim attr As IXMLDOMAttribute
    Dim oXString As String
    Dim chld As Long
    Dim idx As Variant
    Dim addindex As Boolean
    chld = 0
    idx = 0
    addindex = False
    
    
    'determine the node type:
    Select Case inode.NodeType
    
        Case NODE_ELEMENT
            If inode.ParentNode.NodeType = NODE_DOCUMENT Then 'This gets the root node name but ignores all the namespace attributes
                oXString = iXstring & "//" & fp(inode.nodename)
            Else
    
                'Need to deal with indexing. Where an element has siblings with the same nodeName,it needs to be indexed using [index], e.g swapstreams or schedules
    
                For Each chnode In inode.ParentNode.ChildNodes
                    If chnode.NodeType = NODE_ELEMENT And chnode.nodename = inode.nodename Then chld = chld + 1
                Next chnode
    
                If chld > 1 Then '//inode has siblings of the same nodeName, so needs to be indexed
                    'Lookup the index from the indexes array
                    idx = getIndex(inode.nodename, indexes)
                    addindex = True
                Else
                End If
    
                'build the XString
                oXString = iXstring & "/" & fp(inode.nodename)
                If addindex Then oXString = oXString & "[" & idx & "]"
    
                'If type is element then check for attributes
                For Each attr In inode.Attributes
                    'If the element has attributes then extract the data pair XString + Element.Name, @Attribute.Name=Attribute.Value
                    Call oSheet(oSh, oXString & "/@" & attr.Name, attr.Value)
                Next attr
    
            End If
    
        Case NODE_TEXT
            'build the XString
            oXString = iXstring
            Call oSheet(oSh, oXString, inode.NodeValue)
    
        Case NODE_ATTRIBUTE
        'Do nothing
        Case NODE_CDATA_SECTION
        'Do nothing
        Case NODE_COMMENT
        'Do nothing
        Case NODE_DOCUMENT
        'Do nothing
        Case NODE_DOCUMENT_FRAGMENT
        'Do nothing
        Case NODE_DOCUMENT_TYPE
        'Do nothing
        Case NODE_ENTITY
        'Do nothing
        Case NODE_ENTITY_REFERENCE
        'Do nothing
        Case NODE_INVALID
        'do nothing
        Case NODE_NOTATION
        'do nothing
        Case NODE_PROCESSING_INSTRUCTION
        'do nothing
    End Select
    
    'Now call Parser2 on each of inode's children.
    If inode.HasChildNodes Then
        For Each chnode In inode.ChildNodes
            Call Parse2(oSh, chnode, oXString, indexes)
        Next chnode
    Set chnode = Nothing
    Else
    End If
    
    End Sub
    

    Manages the counting of elements using:

    Function getIndex(tag As Variant, indexes) As Variant
    'Function to get the latest index for an xml tag from the indexes array
    'indexes array is passed from one parser function to the next up and down the tree
    
    Dim i As Integer
    Dim n As Integer
    
    If IsArrayEmpty(indexes) Then
        ReDim indexes(1, 0)
        indexes(0, 0) = "Tag"
        indexes(1, 0) = "Index"
    Else
    End If
    For i = 0 To UBound(indexes, 2)
        If indexes(0, i) = tag Then
            'tag found, increment and return the index then exit
            'also destroy all recorded tag names BELOW that level
            indexes(1, i) = indexes(1, i) + 1
            getIndex = indexes(1, i)
            ReDim Preserve indexes(1, i) 'should keep all tags up to i but remove all below it
            Exit Function
        Else
        End If
    Next i
    
    'tag not found so add the tag with index 1 at the end of the array
    n = UBound(indexes, 2)
    ReDim Preserve indexes(1, n + 1)
    indexes(0, n + 1) = tag
    indexes(1, n + 1) = 1
    getIndex = 1
    
    End Function
    

提交回复
热议问题