How can I populate XML with Data in vb.net - vb.net

I have a some XML like below sample which i need to add values/data for the elements. What is the best way to do so short of building a string like
mystr += "<HDR>" & vbCrLf
mystr += "<MESSAGE_ID>" & trim(myMessageID) & "</MESSAGE_ID>" & vbCrLf
mystr += .... and so on
This is what my XML looks like just for reference
<HDR>
<MESSAGE_ID></MESSAGE_ID>
<CCNA></CCNA>
<MSG_TIMESTAMP></MSG_TIMESTAMP>
<TXNUM></TXNUM>
<TXTYP></TXTYP>
<TXACT></TXACT>
<RVER></RVER>
<TEST_PROD_INDICATOR></TEST_PROD_INDICATOR>
</HDR>

The easiest to use way is to use Linq to XML which offers XElement to to represent elements. The elements can be nested to create structures in code that look very similiar to what you have as an XML Document.
Here is a simple example using your sample data with nested elements and the message id set for demonstration purposes.
Sub Main
Dim hdr = New XElement("HDR",
New XElement("MESSAGE_ID", 999999),
New XElement("CCNA"),
New XElement("MSG_TIMESTAMP"),
New XElement("TXNUM"),
New XElement("TXTYP"),
New XElement("TXACT"),
New XElement("RVER"),
New XElement("TEST_PROD_INDICATOR")
)
Console.WriteLine(hdr.ToString())
End Sub
The three most important classes are XDocument, XElement and XAttribute.

Related

Multiple searchTerm

I have the following code trying to find how many times the specific word occurs in the given text. The code works but for only one parameter in the given example for "Dim searchTerm As String = "data". I would like to search for multiple words for example: "data", "separate", "node" etc.
Could someone please help me to modify the existing code to archive the task?
Class CountWords
Shared Sub Main()
Dim text As String = "Historically, the world of data and the world of objects" &
" have not been well integrated. Programmers work in C# or Visual Basic" &
" and also in SQL or XQuery. On the one side are concepts such as classes," &
" objects, fields, inheritance, and .NET Framework APIs. On the other side" &
" are tables, columns, rows, nodes, and separate languages for dealing with" &
" them. Data types often require translation between the two worlds; there are" &
" different standard functions. Because the object world has no notion of query, a" &
" query can only be represented as a string without compile-time type checking or" &
" IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to" &
" objects in memory is often tedious and error-prone."
Dim searchTerm As String = "data"
' Convert the string into an array of words.
Dim dataSource As String() = text.Split(New Char() {" ", ",", ".", ";", ":"},
StringSplitOptions.RemoveEmptyEntries)
' Create and execute the query. It executes immediately
' because a singleton value is produced.
' Use ToLower to match "data" and "Data"
Dim matchQuery = From word In dataSource
Where word.ToLowerInvariant() = searchTerm.ToLowerInvariant()
Select word
' Count the matches.
Dim count As Integer = matchQuery.Count()
Console.WriteLine(count & " occurrence(s) of the search term """ &
searchTerm & """ were found.")
' Keep console window open in debug mode.
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
End Class
' Output:
' 3 occurrence(s) of the search term "data" were found.
Linq is cool but it just does the loops internally so it is not necessarily faster.
Module Module1
Public Sub Main(args As String())
Dim SearchTerms() As String = {"data".ToLowerInvariant, "separate".ToLowerInvariant, "nodes".ToLowerInvariant}
Dim Count = GetCount(SearchTerms)
Dim SearchTerm = String.Join(", ", SearchTerms)
Console.WriteLine($"{Count} occurrence(s) of the search terms {SearchTerm} were found.")
' Keep console window open in debug mode.
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Private Function GetCount(SearchTerms As String()) As Integer
Dim text As String = "Historically, the world of data and the world of objects
have not been well integrated. Programmers work in C# or Visual Basic
and also in SQL or XQuery. On the one side are concepts such as classes,
objects, fields, inheritance, and .NET Framework APIs. On the other side
are tables, columns, rows, nodes, and separate languages for dealing with
them. Data types often require translation between the two worlds; there are
different standard functions. Because the object world has no notion of query, a
query can only be represented as a string without compile-time type checking or
IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to
objects in memory is often tedious and error-prone."
Dim dataSource As String() = text.Split(New Char() {" "c, ","c, "."c, ";"c, ":"c}, StringSplitOptions.RemoveEmptyEntries)
Dim Count As Integer
For Each item In dataSource
'If you want to have a variable number of SearchTerms make a nested For
If item.ToLowerInvariant = SearchTerms(0) Or item.ToLowerInvariant = SearchTerms(1) Or item.ToLowerInvariant = SearchTerms(2) Then
Count += 1
End If
Next
Return Count
End Function
End Module

vb.net Interpolated Strings

I was chastised by a professional developer with a lot of years of experience for Hard Coding my DB name
OK I get it we sometimes carry our bad codding habits with us till we learn the correct way to code
I have finally learned to use Interpolated Strings (personal view they are not pretty)
My Question involves the two Sub's posted below GetDB runs first then HowMany is called from GetDB
Sorry for stating the obvious my reason is I think that NewWord.db gets declared in GetDB and works in HowMany without the same construction Just a Wild Guess
Notice NO $ or quotation used in HowMany
Both Sub's produce desired results
The question is Why don't both statements need to be constructed the same?
Public Sub HowMany()
'Dim dbName As String = "NewWord.db"
Dim conn As New SQLiteConnection("Data Source ='{NewWord.db}';Version=3;")
tot = dgvOne.RowCount ' - 1
tbMessage.Text = "DGV has " & tot.ToString & " Rows"
End Sub
Private Sub GetDB()
Dim str2 As String
Dim s1 As Integer
'Dim dbName As String = "NewWord.db"
Using conn As New SQLiteConnection($"Data Source = '{"NewWord.db"}' ;Version=3;")
conn.Open()
That second method is a ridiculous and pointless use of string interpolation. What could possibly be the point of inserting a literal String into a literal String? The whole point is that you can insert values determined at run time. That second code is equivalent to using:
"Data Source = '" & "NewWord.db" & "' ;Version=3;"
What's the point of that? The idea is that you retrieve your database name from somewhere at run time, e.g. your config file, and then insert that into the template String, e.g.
Dim dbName = GetDbNameFromExternalFile()
Using conn As New SQLiteConnection($"Data Source = '{dbName}' ;Version=3;")
Now the user can edit that external file to change the database name after deploying the application. How could they change the name in your code?
To be clear, string interpolation is just native language support for the String.Format method. You can see that if you make a mistake that generates an exception and the that exception will refer to the String.Format method. In turn, String.Format is a way to make code that multiple values into a long template easier to read than if multiple concatenation operators were used.
Having lots of quotes and ampersands makes code hard to read and error-prone. I've lost count of the number of times people miss a single quote or a space or the like in a String because they couldn't read there messy code. Personally, I'll rarely use two concatenation operators in the same expression and never three. I'll do this:
Dim str = "some text" & someVar
but I'll rarely do this:
Dim str = "some text" & someVar & "some more text"
and I'll never do this:
Dim str = "some text" & someVar & "some more text" & someOtherVar
Before string interpolation, I would use String.Format:
Dim str = String.Format("some text{0}some more text{1}", someVar, someOtherVar)
Nowadays, I'll generally use string interpolation:
Dim str = $"some text{someVar}some more text{someOtherVar}"
Where I may still use String.Format over string interpolation is if one value is getting inserted in multiple places and/or where the text template and/or the expressions are long so that I can break the whole thing over multiple lines, e.g.
Dim str = String.Format("some text{0}some more text{1}yet more text{0}",
someVar,
someOtherVar)
I have no idea what NewWord.db is so I made a class to represent it.
Public Class NewWord
Public Shared Property db As String = "The db Name"
End Class
HowMany is not a very good name for your sub. Try to use more descriptive names.
The first sub doesn't even use the connection. The connection string in that code is a literal string. It will not consider NewWord.db as a variable. You will not notice this because you never attempt to open the connection. In my version you check the connection string with a Debug.Print.
I changed the last line to use and interpolated string. It is not necessary to call .ToString on tot.
Private Sub DisplayGridCount()
Dim conn As New SQLiteConnection("Data Source ='{NewWord.db}';Version=3;")
Debug.Print(conn.ConnectionString)
Dim tot = DataGridView1.RowCount
TextBox1.Text = $"DGV has {tot} Rows"
End Sub
The second snippet starts off with 2 unused variables. I deleted them. Again, the Debug.Print to show the difference in the 2 strings.
Private Sub TestConnection()
Using conn As New SQLiteConnection($"Data Source = '{NewWord.db}' ;Version=3;")
Debug.Print(conn.ConnectionString)
'conn.Open()
End Using
End Sub
As to where to store connection strings see https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/protecting-connection-information and Where to store Connection String

In VB, how do I use IndexOf function to find the second time something appears

I am writing a function that takes the HTML code from a website, looks at the name of which span class I want to extract some information from and then extract it. One of the other parameters I am trying to add to my function is a number which specifies which span class you want to search for (whether it is the first, second or third etc. occurrence)
I have gotten the main part of the function working (finding the span class an extracting it's information), but I want to get the "occurrence" part working too.
Here is my code:
Function RetrieveClass(ByRef URL, ByRef ClassToRetrieve, ByRef ClassIndex)
Const QUOTE = """"
'Loading the website's HTML code and storing it in a HTML as a string:
Dim Client As New WebClient
'URL = "https://jisho.org/search/%E5%8F%AF%E6%84%9B%E3%81%84" 'used to test on the 可愛い page
Dim HTML As String = Client.DownloadString(New Uri(URL))
'Used to debug:
Console.WriteLine(HTML)
Console.WriteLine("URL: " & URL)
Dim SnipIndex As Integer = HTML.IndexOf("class=" & QUOTE & ClassToRetrieve) 'Start of the snip, this will look for the class name, example: <span class="meaning-meaning">cute; adorable; charming; lovely; pretty</span>
If SnipIndex = -1 Then
Return ("Error: |" & "span class=" & QUOTE & ClassToRetrieve & "| Not Found")
End If
Dim Snip As String = Mid(HTML, SnipIndex + 10 + ClassToRetrieve.length, 50)
SnipIndex = Snip.IndexOf("<")
Snip = Left(Snip, SnipIndex)
Console.WriteLine("SnipEnd: " & SnipIndex)
Console.WriteLine("Snip: " & Snip)
Console.ReadLine()
Return (Snip)
End Function
Some context: I am trying create a web scraper that takes definitions and more from a Japanese dictionary, this will be helpful for my language learning.
If you look,
Dim SnipIndex As Integer = HTML.IndexOf("class=" & QUOTE & ClassToRetrieve) is the line that finds the class that you are searching for. What I want is the IndexOf function to search for the second occurrence of the span class.
Thanks
I would suggest to use a simple for loop and run it n times. (searching the n'th appearance) Inside the loop you call indexOf(string, number), the number you can take from the previous runs index + length of the string. That way the second time the loop runs, it starts searching after the first appearance. And so on. You can simply save the index in a variable and use that to calculate where to start the next search. Initialize the variable with 0 before the loop...
Edit to clarify: You would have something like index = indexOf(string, index + string.length)
There might be a better way to do this, but this would definitely work.

Splitting string in VB.NET produces unusual results

I am using the Split function in VB.NET, and it is producing a weird result when I display the output.
I have an XML document, and I just want to loop through each <backup> tag in the document, so I am using:
Dim XMLString As String
XMLString = "<backup>INFO</backup><backup>ANOTHER INFO</backup>"
Dim SplitBackup As String()
SplitBackup = XMLString.Split("<backup>")
For Each BackupContent In SplitBackup
MsgBox(BackupContent)
Next
Now, one would expect this to output INFO in a MsgBox, I click OK and then another one would popup and show 'ANOTHER INFO', but it seems that the Split function is getting stuffed up with the '<' and '>' in it. Is there someway I can get around this by escaping it, or parsing it some other way.
Any suggestions are much appreciated!
Give XML a chance.
Dim bups As XElement = <backups><backup>INFO</backup><backup>ANOTHER INFO</backup></backups>
For Each xe As XElement In bups.Elements
Debug.WriteLine(xe.Value)
Next
One possibility to do this is to use regular expression to split the tags (and escape the problematic symbols) and then use LINQ to Objects to get the value from each tag:
Dim XMLString As String = "<backup>INFO</backup><backup>ANOTHER INFO</backup>"
Dim words = Regex.Split(XmlString, "\<backup\>").Where(function(f) not String.IsNullOrEmpty(f)).Select(function(f) f.Replace("</backup>", String.Empty)) '
for each word in words
Console.WriteLine(word)
next word
The output is:
INFO
ANOTHER INFO
What the code does:
Dim words = Regex
' split on every tag
.Split(XmlString, "\<backup\>")
' remove empty items
.Where(function(f) not String.IsNullOrEmpty(f))
' remove trailing closing tag and thus retrieve the value within
.Select(function(f) f.Replace("</backup>", String.Empty))
As already suggested you better learn how to use the build-in XML support - it is easier and safer because you do not need to pay attention to the brackets - < and > are automatically handled. A possible solution could look like this (! you need to have a valid XML structure - one unique root node!):
' !!! you need to have a valid XML element - one root node !!!
Dim XMLString As String = "<root><backup>INFO</backup><backup>ANOTHER INFO</backup></root>"
dim words = XDocument.Parse(XMLString).Root.Descendants("backup").Select(function (f) f.Value)
for each word in words
Console.WriteLine(word)
next word
The output is the same as above. How does the code work:
dim words = XDocument
' parse the specified XML structure; use Load("file.xml") to load from file
.Parse(XMLString)
' from the root node
.Root
' take all nodes matching the specified tag
' note - no need to pay attention to the < and >
.Descendants("backup")
' select the value of the XML node
.Select(function (f) f.Value)
You would need to get rid of the close element.
So you could use:
Dim XMLString As String
XMLString = "<backup>INFO</backup><backup>ANOTHER INFO</backup>"
Dim SplitBackup As String()
SplitBackup = XMLString.Split("<backup>")
For Each BackupContent In SplitBackup
Dim Something() as string
Something = BackupContent.Split("</backup">)
MsgBox(Something(0))
Next
Not the most elegant coding though.

Retrieving data from xml using xmlDocument, xmlNode and xmlNodelist

This is a sample code in vb.net in which i retrieve the details of elements without attributes.
For Each standardItemInfoNode In ItemInfoNodes
baseDataNodes = ItemInfoNodes.ChildNodes
bFirstInRow = True
For Each baseDataNode As XmlNode In baseDataNodes
If (bFirstInRow) Then
bFirstInRow = False
Else
Response.Write("<br>")
End If
Response.Write(baseDataNode.Name & ": " & baseDataNode.InnerText)
Next
Next
How can i retrieve the details of the xml like having node with attributes and its child also having attributes. I need to retrieve all the attributes of node and its child node which are present in the middle of other xml tags.
I'm not sure exactly what you're asking, and I can't give you a specific example without knowing the format of the XML you are trying to process, but I think what you are looking for is the Attributes property of the XmlNode objects. Each XmlNode has an Attributes property that allows you to access all the attributes for that node. Here's the MSDN page that explains it (and provides a simple example):
http://msdn.microsoft.com/en-us/library/7f285y48.aspx
EDIT:
Using the example XML you posted in the comment, you could read the all the values and attributes like this:
Dim doc As XmlDocument = New XmlDocument()
doc.LoadXml("<EventTracker><StandardItem><Header1>Header1 Text</Header1> <Header2>Header2 Text</Header2></StandardItem><Item> <Events> <EventSub EventId='73' EventName='Orchestra' Description='0'> <Person PersonId='189323156' PersonName='Chandra' Address='Arunachal'/><Person PersonId='189323172' PersonName='Sekhar' Address='Himachal'/></EventSub> </Events> </Item> </EventTracker>")
Dim header1 As String = doc.SelectSingleNode("EventTracker/StandardItem/Header1").InnerText
Dim header2 As String = doc.SelectSingleNode("EventTracker/StandardItem/Header2").InnerText
For Each eventSubNode As XmlNode In doc.SelectNodes("EventTracker/Item/Events/EventSub")
Dim eventId As String = eventSubNode.Attributes("EventId").InnerText
Dim eventName As String = eventSubNode.Attributes("EventName").InnerText
Dim eventDescription As String = eventSubNode.Attributes("Description").InnerText
For Each personNode As XmlNode In eventSubNode.SelectNodes("Person")
Dim personId As String = personNode.Attributes("PersonId").InnerText
Dim personName As String = personNode.Attributes("PersonName").InnerText
Dim personAddress As String = personNode.Attributes("Address").InnerText
Next
Next
However, if you are loading all the data in the XML like this, I would recommend deserializing the XML into an EventTracker object. Or, as I said in my comment on your post, if the only purpose for reading the XML document is to transform it into another XML or HTML document, I would recommend using XSLT, instead.
If you want to test if an attribute exists, you can do something like this:
Dim attribute As XmlNode = personNode.Attributes.GetNamedItem("PersonId")
If attribute IsNot Nothing Then
Dim personId As String = attribute.InnerText
End If
However, this would be much easier with serialization since the deserialized object would simply have null properties for any elements that didn't exist.
You can use SelectSingleNode("XPath or NodeName") and loop through the Attributes.Item(index) on that node. You can also, if you know the childnode name in advance, loop through SelectSingleNode("XPath Or NodeName").SelectSingleNode("XPath or ChildName").Attributes.Item(index).