Hello
I have found that Me.ChildNodes does not seem to remove children from the underlying XmlDocument, even if I called multiple SelectNodes on the same XmlDocument object? Maybe this is becuase of the newer CF?
Anyway I found that Me.ChildNodes was much much faster than Me.Clone.ChildNodes. I also extended the original a little to support a few more Xpath style queries namely:
Filter by child element:
selectSingleNode("tables/table[name=Customers]")Filter by node match index:
selectSingleNode("tables/table[n]")Its not extensively tested but works so far for me.
Brian Norman
www.bbpsoftware.co.uk
Imports System.Xml
Public Class XmlDoc : Inherits XmlDocument
Public Function selectSingleNode(ByVal cXPath As String) As XmlNode
Dim aQuery() As String = cXPath.Split("/")
Dim oNodeList As XmlNodeList = Me.ChildNodes()
Dim nI As Integer
For nI = 0 To aQuery.Length - 2
GetFirstMatchedNodes(oNodeList, aQuery(nI))
Next
Return GetNodeFromList(oNodeList, aQuery(aQuery.Length - 1))
End Function
Public Function selectNodes(ByVal cXPath As String) As XmlNodeList
Dim aQuery() As String = cXPath.Split("/")
Dim oNodeList As XmlNodeList = Me.ChildNodes()
Dim nI As Integer
For nI = 0 To aQuery.Length - 2
GetFirstMatchedNodes(oNodeList, aQuery(nI))
Next
GetAllMatchedNodes(oNodeList, aQuery(aQuery.Length - 1))
Return oNodeList
End Function
Private Sub GetAllMatchedNodes(ByRef oNodeList As XmlNodeList, _
ByVal cXPath As String)
Dim cQuery, aParams() As String
Dim nI As Integer
ParseXPath(cXPath, cQuery, aParams)
nI = 0
Do While nI <= oNodeList.Count - 1
If oNodeList.Item(nI).Name = cQuery Then
If Not MatchXPathParams(aParams, oNodeList.Item(nI), nI) Then
oNodeList.Item(nI).ParentNode.RemoveChild(oNodeList.Item(nI))
Else
nI += 1
End If
Else
oNodeList.Item(nI).ParentNode.RemoveChild(oNodeList.Item(nI))
End If
Loop
End Sub
Private Sub GetFirstMatchedNodes(ByRef oNodeList As XmlNodeList, _
ByVal cXPath As String)
Dim cQuery, aParams() As String
Dim nI As Integer
ParseXPath(cXPath, cQuery, aParams)
For nI = 0 To oNodeList.Count - 1
If oNodeList.Item(nI).Name = cQuery Then
If MatchXPathParams(aParams, oNodeList.Item(nI), nI) Then
oNodeList = oNodeList.Item(nI).ChildNodes
Exit For
End If
End If
Next
End Sub
Private Function GetNodeFromList(ByRef oNodeList As XmlNodeList, _
ByVal cXPath As String) As XmlNode
Dim cQuery, aParams() As String
Dim nI As Integer
ParseXPath(cXPath, cQuery, aParams)
For nI = 0 To oNodeList.Count - 1
If oNodeList.Item(nI).Name = cQuery Then
If MatchXPathParams(aParams, oNodeList.Item(nI), nI) Then
Return oNodeList.Item(nI)
End If
End If
Next
End Function
Private Sub ParseXPath(ByVal cXPath As String, _
ByRef cQuery As String, _
ByRef aParams() As String)
Dim nIndex As Integer
nIndex = cXPath.IndexOf("[")
If nIndex <> -1 Then
cQuery = cXPath.Substring(0, nIndex)
cXPath = cXPath.Substring(nIndex + 1)
cXPath = cXPath.Replace("]", "")
aParams = cXPath.Split("[")
Else
cQuery = cXPath
ReDim aParams(-1)
End If
End Sub
Private Function MatchXPathParams(ByRef aParams() As String, _
ByRef oNode As XmlNode, ByVal nNodeIndex As Integer) As Boolean
Dim nI, nJ, nIndex As Integer
Dim cNodeName, cNodeVal As String
Dim bMatches As Boolean
If aParams.Length = 0 Then
Return True
End If
bMatches = True
For nI = 0 To aParams.Length - 1
nIndex = aParams(nI).IndexOf("=")
cNodeVal = aParams(nI).Substring(nIndex + 1)
' check if parameter is attributes (and so start with '@')
If aParams(nI).Substring(0, 1) = "@" Then
'is attribute
cNodeName = aParams(nI).Substring(1, nIndex - 1)
For nJ = 0 To oNode.Attributes.Count - 1
If oNode.Attributes(nJ).Name = cNodeName Then
If oNode.Attributes(nJ).InnerText <> cNodeVal Then
bMatches = False
End If
Exit For
ElseIf nJ = oNode.Attributes.Count - 1 Then
bMatches = False
End If
Next
Else
'check if param is nodelist index
If IsNumeric(aParams(nI)) Then
'is index
If Not nNodeIndex.ToString = aParams(nI) Then
bMatches = False
End If
Else
'is element
cNodeName = aParams(nI).Substring(0, nIndex)
For nJ = 0 To oNode.Attributes.Count - 1
If oNode.ChildNodes(nJ).Name = cNodeName Then
If oNode.ChildNodes(nJ).InnerText <> cNodeVal Then
bMatches = False
End If
Exit For
ElseIf nJ = oNode.ChildNodes.Count - 1 Then
bMatches = False
End If
Next
End If
End If
Next
Return bMatches
End Function
End Class