Hi all!

Here's a simple XML parser written with pure VB. The code can be found below. (You might ask why I did this. Do I need to have a reason?)

How it works is that every <tag></tag> is created as a class called XMLToken. An XMLToken has 4 properties: name, attributes, value, and a list of child tokens/subtokens. An XMLToken cannot (should not) have both a value property and a child tokens property.

vb Code:
  1. Option Strict On
  2. Option Explicit On
  3.  
  4. Namespace XML
  5.  
  6.     ''' <summary>
  7.     ''' Represents an entire XML document.
  8.     ''' </summary>
  9.     Class XMLDoc
  10.         Inherits XMLToken
  11.  
  12.         ''' <summary>
  13.         ''' Creates a blank XML document.
  14.         ''' </summary>
  15.         Sub New()
  16.             MyBase.New("XML", "")
  17.         End Sub
  18.  
  19.         ''' <summary>
  20.         ''' Creates and automatically parses an XML document from an existing string.
  21.         ''' </summary>
  22.         ''' <param name="XMLString">Existing XML String</param>
  23.         Sub New(XMLString As String)
  24.             MyBase.New("XML", XMLString)
  25.         End Sub
  26.  
  27.         ''' <summary>
  28.         ''' Writes this element as a string.
  29.         ''' </summary>
  30.         Public Overrides Function ToString() As String
  31.             Dim TempVal As String = ""
  32.             For i As Int32 = 0 To Tokens.Count - 1 Step 1
  33.                 TempVal &= Tokens(i).ToString & vbNewLine
  34.             Next
  35.             Return TempVal
  36.         End Function
  37.  
  38.     End Class
  39.  
  40.     ''' <summary>
  41.     ''' Represents an XML Token with 4 properties: Name, Attributes, Value, and Child Tokens. Note: A token cannot have both a value and child tokens property.
  42.     ''' </summary>
  43.     Class XMLToken
  44.  
  45.         ''' <summary>
  46.         ''' The name (tag) of the token.
  47.         ''' </summary>
  48.         Property Name As String
  49.         ''' <summary>
  50.         ''' The attributes associated with the element, may be blank.
  51.         ''' </summary>
  52.         Property Attributes As String
  53.         ''' <summary>
  54.         ''' The value of the token.
  55.         ''' </summary>
  56.         Property Value As String
  57.         ''' <summary>
  58.         ''' A list of child tokens.
  59.         ''' </summary>
  60.         Property Tokens As List(Of XMLToken)
  61.  
  62.         ''' <summary>
  63.         ''' Programatically creates a new XMLToken.
  64.         ''' </summary>
  65.         ''' <param name="Name_New">Name (tag) Property</param>
  66.         ''' <param name="Value_New">Value Property (Can be written in XML, automatically parsed)</param>
  67.         Sub New(Name_New As String, Value_New As String)
  68.             Name = Name_New
  69.             Attributes = ""
  70.             Value = Value_New
  71.             Tokens = New List(Of XMLToken)
  72.             Search(Value.Trim)
  73.         End Sub
  74.  
  75.         ''' <summary>
  76.         ''' Manually creates a new XMLToken.
  77.         ''' </summary>
  78.         ''' <param name="Name_New">Name (tag) Property</param>
  79.         ''' <param name="Children">The child tokens as a list.</param>
  80.         Sub New(Name_New As String, Children As List(Of XMLToken))
  81.             Name = Name_New
  82.             Attributes = ""
  83.             Value = ""
  84.             Tokens = New List(Of XMLToken)(Children)
  85.         End Sub
  86.  
  87.         ''' <summary>
  88.         ''' Programatically creates a new XMLToken.
  89.         ''' </summary>
  90.         ''' <param name="Name_New">Name (tag) Property</param>
  91.         ''' <param name="Attributes_New">Attributes Property (written="like this")</param>
  92.         ''' <param name="Value_New">Value Property (Can be written in XML, automatically parsed)</param>
  93.         Sub New(Name_New As String, Attributes_New As String, Value_New As String)
  94.             Name = Name_New
  95.             Attributes = Attributes_New.Trim
  96.             Value = Value_New
  97.             Tokens = New List(Of XMLToken)
  98.             Search(Value.Trim)
  99.         End Sub
  100.  
  101.         ''' <summary>
  102.         ''' Manually creates a new XMLToken.
  103.         ''' </summary>
  104.         ''' <param name="Name_New">Name (tag) Property</param>
  105.         ''' <param name="Attributes_New">Attributes Property (written="like this")</param>
  106.         ''' <param name="Children">The child tokens as a list.</param>
  107.         Sub New(Name_New As String, Attributes_New As String, Children As List(Of XMLToken))
  108.             Name = Name_New
  109.             Attributes = Attributes_New.Trim
  110.             Value = ""
  111.             Tokens = New List(Of XMLToken)(Children)
  112.         End Sub
  113.  
  114.         ''' <summary>
  115.         ''' A somewhat recursive function that creates new tokens and child tokens.
  116.         ''' </summary>
  117.         ''' <param name="TokenString">The string to search for tokens, usually the parent token's value.</param>
  118.         Private Sub Search(TokenString As String)
  119.             Dim Another As Boolean = False
  120.             For i As Int32 = 0 To TokenString.Count - "<_></_>".Length Step 1
  121.                 If TokenString(i) = "<"c Then
  122.                     i += 1
  123.                     Dim NameEnd As Int32 = -1
  124.                     For j As Int32 = i + 1 To TokenString.Count - "></_>".Length Step 1
  125.                         If (TokenString(j) = " "c OrElse TokenString(j) = ">"c) AndAlso NameEnd = -1 Then NameEnd = j
  126.                         If TokenString(j) = ">"c Then
  127.                             Dim TokenName As String = TokenString.Substring(i, NameEnd - i)
  128.                             Dim TokenAttr As String = TokenString.Substring(NameEnd, j - NameEnd)
  129.                             Dim TokenEnd As String = $"</{TokenName}>"
  130.                             j += 1
  131.                             For k As Int32 = j To TokenString.Length - TokenEnd.Length
  132.                                 If TokenString.Substring(k, TokenEnd.Length) = TokenEnd Then
  133.                                     Dim TokenValue As String = TokenString.Substring(j, k - j)
  134.                                     Tokens.Add(New XMLToken(TokenName, TokenAttr, TokenValue)) ' SUCCESS!
  135.                                     i = k + TokenEnd.Length
  136.                                     If i >= TokenString.Count Then Exit Sub
  137.                                     Another = True
  138.                                     Exit For
  139.                                 End If
  140.                             Next
  141.                             If Another Then Exit For
  142.                         End If
  143.                     Next
  144.                     Another = False
  145.                 End If
  146.             Next
  147.         End Sub
  148.  
  149.         ''' <summary>
  150.         ''' Retrieves all the child tokens with a specific name.
  151.         ''' </summary>
  152.         ''' <param name="TokenName">The name of the token.</param>
  153.         Function GetToken(TokenName As String) As List(Of XMLToken)
  154.             Dim L As New List(Of XMLToken)
  155.             For i As Int32 = 0 To Tokens.Count - 1 Step 1
  156.                 If Tokens(i).Name = TokenName Then L.Add(Tokens(i))
  157.             Next
  158.             Return L
  159.         End Function
  160.  
  161.         ''' <summary>
  162.         ''' Writes this element as a string.
  163.         ''' </summary>
  164.         Public Overrides Function ToString() As String
  165.             If Tokens.Count > 0 Then
  166.                 Dim TempVal As String = vbNewLine
  167.                 For i As Int32 = 0 To Tokens.Count - 1 Step 1
  168.                     TempVal &= Tokens(i).ToString & vbNewLine
  169.                 Next
  170.                 Return $"<{Name}{If(Attributes.Length > 0, " ", "")}{Attributes}>{TempVal}</{Name}>"
  171.             End If
  172.             Return $"<{Name}{If(Attributes.Length > 0, " ", "")}{Attributes}>{Value}</{Name}>"
  173.         End Function
  174.  
  175.     End Class
  176.  
  177. End Namespace

In the next post, I will demonstrate how to retrieve XML information using this tool. I will also show how to create XML documents from a "tree" of XMLTokens.