Read a parent and child node from xml - vb.net

I am trying to get 2 values out of an XML.
Currently, when I run the code below, I get just the information in "OutTime". I know why this is happening, but I am unsure how to change it to get the information I would like.
What I would like displayed is: All names under the 'People' and the 'OutTime'.
Example:
OutPut:
S7-JEHILL 20:47
XML Sheet
<Times>
<People>
<S7-JEHILL>
<OutTime>20:47</OutTime>
</S7-JEHILL>
</People>
</Times>
Current Code
Dim xmlDoc As New XmlDocument()
xmlDoc.Load("C:\Users\jefhill\Desktop\TimeStamps.xml")
Dim child As XmlNode = xmlDoc.SelectSingleNode("/Times/People")
If Not (child Is Nothing) Then
Dim nr As New XmlNodeReader(child)
While nr.Read()
NameList.Items.Add(nr.Value)
End While
End If

Add System.XML to your Reference. This is just another approach for XML file nodes manipulation.
Dim xmlDoc As New XmlDocument 'For loading xml file to read
Dim ArticleNodeList As XmlNodeList 'For getting the list of main/parent nodes
xmlDoc.Load("C:\Users\jefhill\Desktop\TimeStamps.xml") 'loading the xml file, insert your file here
ArticleNodeList = xmlDoc.GetElementsByTagName("People") 'Setting all <People> node to list
For Each articlenode As XmlNode In ArticleNodeList 'Looping through <People> node
For Each basenode As XmlNode In articlenode 'Looping all <People> childnodes
Dim result As String = ""
result = basenode.Name 'use .name to get the xml node name
For Each Node As XmlNode In basenode 'Looping all childnodes of basenode
result = result & " " & Node.InnerText 'use .Innertext to get the xml node value
Next
NameList.Items.Add(result) 'Adding Value to your variable
Next
Next

First use an XPath query to get all nodes under the tag. Then use the ChildNodes collections to get the relevant information of a) the tag name and b) the OutTime value:
Sub Main()
Dim Xml As String = "<Times><People><S7-JEHILL><OutTime>20:47</OutTime></S7-JEHILL></People></Times>"
Dim Doc As New Xml.XmlDocument
Dim Xpath As String = "/Times/People"
Dim ElementList As Xml.XmlNodeList = doc.SelectNodes(xpath)
Dim PersonName, OutTime As String
'load xml to document
Doc.LoadXml(Xml)
'iterate elements in <People>
For Each Element As Xml.XmlElement In ElementList
'gets the S7-JEHILL value from the tag name
PersonName = Element.ChildNodes(0).Name
'gets the 20:47 from the tag value i.e. inner XML
OutTime = Element.ChildNodes(0).ChildNodes(0).InnerXml
Console.WriteLine(String.Format("{0} {1}", PersonName, OutTime))
Next
Console.ReadKey()
End Sub

Related

Parsing through DataTable for matching value and creating a new DataTable from the results

In VB.NET I'm trying to count through the value's in a list, until the value for "stock" in my DataTable, Boxes, is equal to the value in my list. When this occurs a row should be created in my new DataTable "output". I would then continue counting through the list looking for other matching instances to add into "output".
So far counting through the list and then within that count going through the datatable to match value's works wonderfully. The part where I'm getting hung up is when I try to take the matching row and put it into another table.
Dim output As DataTable
Dim jsonstringy As String = BoxComms.WebGet("http://foo.foo.foo") 'PULLS JSON STRING
Dim Boxes = Newtonsoft.Json.JsonConvert.DeserializeObject(Of DataTable)(jsonstring)
Dim MyString As String = TextBox1.Text 'MAKE STRING OF STOCK #'s FROM TEXTBOX
MyString = MyString.Replace(" ", "") 'GET RID OF SPACES
Dim MyArray() As String = MyString.Split(",") 'SEPERATE COMMA DELIMETED LIST
Dim MyList As List(Of String) = MyArray.ToList()
For Each value In MyList 'COUNT THROUGH LIST OF STOCK #'s
For Each row As DataRow In Boxes.Rows
If row("stock") = value Then 'IF STOCK # IS EQUAL TO ANY OF NUMBERS IN TEXTBOX
output.ImportRow(row) 'ADD ROW FROM DATATABLE Boxes to DATATABLE output
End If
Next row
Next
The solution was fairly simple, my DataTable needed a schema first. in order to copy the schema all I needed was to initialize the new table as a clone. to do so the code was as follows.
Dim output As DataTable = Boxes.Clone()
clone vs copy. copy get's the schema and data clone just gets the schema. then as I was parsing through the first table looking for matches I had to add the row to my new table with the following code.
output.Rows.Add(row.ItemArray)
the full code is as follows
Dim jsonstring As String = BoxComms.WebGet("https://foo.foo.foo")
Dim Boxes = Newtonsoft.Json.JsonConvert.DeserializeObject(Of DataTable)(jsonstring)
Dim output As DataTable = Boxes.Clone()
Dim MyString As String = TextBox1.Text
MyString = MyString.Replace(" ", "")
Dim MyArray() As String = MyString.Split(",")
Dim MyList As List(Of String) = MyArray.ToList()
For Each value In MyList
For Each row As DataRow In Boxes.Rows
If row("stock") = value Then
Console.WriteLine(row("stock"))
output.Rows.Add(row.ItemArray)
End If
Next row
Next
BoxControl.DataGridView1.DataSource = output
Me.Close()
End If

How to read attribute value of xml

How can i read attribute value of a xml.
I have this below xml and i am working with windows forms vb.net
I tried something like this below but does not work. I want to read connection string value
Dim xe As XElement = XElement.Load("..\\..\\KMMiddleTier.xml")
Dim name = From nm In xe.Elements("ConnectionKey") Where nm.Element("ConnectionKey").Attribute("Key") = "DB_DEV" Select nm.Element("ConnectionKey").Attribute("ConnectionString").Value.FirstOrDefault()
Dim xmlDoc as XMLDocument
Dim xmlNodeList As XmlNodeList = xmlDoc.SelectNodes("/KMMiddleTierSecurity/ConnectionKeys/ConnectionKey")
Dim strConnectionKey As String = xmlNodeList.Item(0).Attributes("ConnectionString").Value''''
This might help.

VB - Issue using XPath reading an XML

I am currently trying to read in an XML node from a filepath which I pass to my method.
Public Function ReadXMLForIsite(xmlFileName As String)
Dim IsitePath As String
Dim doc As New XPathDocument(xmlFileName)
Dim nav As XPathNavigator
Dim iter As XPathNodeIterator
nav = doc.CreateNavigator
iter = nav.Select("GovTalkMessage/Header") 'Node name
'Loop through the records in that node
While iter.MoveNext
Dim lstNav As XPathNavigator
'Get the data we need from the node
Dim iterNews As XPathNodeIterator
lstNav = iter.Current
iterNews = lstNav.SelectDescendants(XPathNodeType.Element, False)
'Loop through the child nodes
While iterNews.MoveNext
Debug.WriteLine(iterNews.Current.Name & ": " & iterNews.Current.Value)
End While
End While
Return IsitePath
End Function
Every time i run this method (even with different node names) the variable 'iter' states that 'debugger display proxy is a type and cannot be used as an expression'. This occurs just before the while statement, therefore does not go in. Any help would be much appreciated. Thanks!
Try to load your Xml into an XDocument.
Dim xdoc As XDocument = XDocument.Load("X:\Jacob.Freeman\RTI\TestXML\0001R.xml")
Dim headerNode = xdoc.Descendants.First(Function(x) x.Name.LocalName = "Header")
For Each desc In headerNode.Descendants()
Console.WriteLine(desc.Name.LocalName + ":" + desc.Value)
Next
Console.ReadLine()

HtmlAgilityPack : How do I combine html elements together into one tag with a class?

Issue:
I need to examine some HTML elements using HtmlAgilityPack and combine the tag names.
Is it possible to extract each tag, from the parent to the child, replacing it with a span that has a class with a name of “strikeUEmStrong”. Also, the name changes based on the HTML element.
Order of the name of the class does in fact matter, I realized this through trial and error. As long as its able to get all of the elements and combine them together. It is very possible that it will have multiple text nodes with various levels of formatting.
This will affect multiple paragraphs.
For example, if I have this html code:
<p>
<strike><u><em><strong>four styles</strong></em></u></strike></p>
How do I convert it to this:
<p>
<span class="strikeUEmStrong">four styles</span></p>
Its possible to have this type of code as well:
<p>
<strike><u><em><strong>four styles</strong></em></u></strike> <strike><u><em>three styles</em></u></strike></p>
<p>
<em><strong>two styles</strong></em></p>
The output should look like this:
<p>
<span class="strikeUEmStrong">four styles</span> <span class="strikeUEm">three styles<span></p><p><span class="emStrong">two styles<span></p>
Prototype:
'Retrive the class name of each format node
Function GetClassName(ByVal n As HtmlNode) As String
Dim ret As String = String.Empty
If (n.Name <> "#text") And (n.Name <> "p") Then
ret = n.Name + " "
End If
'Get the next node
For Each child As HtmlNode In n.ChildNodes
ret &= GetClassName(child)
Next
Return ret
End Function
'Create a list of class names
Function GetClassNameList(ByVal classNameList As String) As List(Of String)
Dim ret As New List(Of String)
Dim classArr() As String = classNameList.Split(" ")
For Each className As String In classArr
ret.Add(className)
Next
Return ret
End Function
'Sort a list of class names and return a merged class string
Function GetSortedClassNameString(ByVal classList As List(Of String)) As String
Dim sortedMergedClass As String = String.Empty
classList.Sort()
For Each className As String In classList
sortedMergedClass &= className
Next
Return sortedMergedClass
End Function
'Lets point to the body node
Dim bodyNode As HtmlNode = htmlDoc.DocumentNode.SelectSingleNode("//body")
'Lets create some generic nodes
Dim currPNode As HtmlNode
Dim formatNodes As HtmlNodeCollection
Dim text As String = String.Empty
Dim textSize As Integer = 0
'Make sure the editor has something in it
If editorText <> "" Then
'Send the text from the editor to the body node
If bodyNode IsNot Nothing Then
bodyNode.InnerHtml = editorText
End If
Dim pNode = bodyNode.SelectNodes("//p")
Dim span As HtmlNode = htmlDoc.CreateElement("span")
Dim tmpBody As HtmlNode = htmlDoc.CreateElement("body")
Dim textNode As HtmlNode = htmlDoc.CreateTextNode
Dim pCount As Integer = bodyNode.SelectNodes("//body/p").Count - 1
For childCountP As Integer = 0 To pCount
Dim paragraph = HtmlNode.CreateNode(htmlDoc.CreateElement("p").WriteTo)
'Which paragraph I am at.
currPNode = pNode.Item(childCountP)
'For this paragraph get me the collection of html nodes
formatNodes = currPNode.ChildNodes
'Count how many Format nodes we have in a paragraph
Dim formatCount As Integer = currPNode.ChildNodes.Count - 1
'Go through each node and examine the elements.
'Then look at the markup to create classes and then group them under one span
For child As Integer = 0 To formatCount
'Iterate through the formateNodes, strike, em, strong, etc.
Dim currFormatNode = HtmlNode.CreateNode(formatNodes(child).WriteTo)
'TODO: Handle nested images and links? How do we know what to rip out?
'First check for format nodes
'Note, we can't let it use everything because it will change nested elements as well. I.E. span within span.
If (currFormatNode.Name <> "#text") And (currFormatNode.Name = "strike") Or (currFormatNode.Name = "em") _
Or (currFormatNode.Name = "strong") Or (currFormatNode.Name = "u") Or (currFormatNode.Name = "sub") _
Or (currFormatNode.Name = "sup") Or (currFormatNode.Name = "b") Then
'strip all tags, just take the inner text
span.InnerHtml = currFormatNode.InnerText
'Create a text node with text from the lowest node
textNode = htmlDoc.CreateTextNode(span.InnerText)
'Recursively go through the format nodes
'Create a list from the string
'Then sort the list and return a string
'Appending the class to the span
span.SetAttributeValue("class", GetSortedClassNameString(GetClassNameList(GetClassName(currFormatNode).Trim())))
'Attach the span before the current format node
currFormatNode.ParentNode.InsertBefore(span, currFormatNode)
'Remove the formatted children leaving the above node
currFormatNode.ParentNode.ChildNodes.Remove(currFormatNode)
'We need to build a paragraph here
paragraph.InnerHtml &= span.OuterHtml
'Lets output something for debugging
childNodesTxt.InnerText &= span.OuterHtml
Else 'handle #text and other nodes seperately
'We need to build a paragraph here
paragraph.InnerHtml &= span.OuterHtml
textNode = htmlDoc.CreateTextNode(currFormatNode.InnerHtml)
'Lets output something for debugging
childNodesTxt.InnerText &= textNode.OuterHtml
End If
Next
'End of formats
'Start adding the new paragraph's to the body node
tmpBody.AppendChild(paragraph)
Next
'End of paragraphs
'Clean out body first and replace with new elements
htmlDoc.DocumentNode.SelectSingleNode("//body").Remove()
'Update our body
htmlDoc.DocumentNode.SelectSingleNode("//html").AppendChild(tmpBody)
End If
htmlDoc.Save(Server.MapPath("html\editor.html"))
End If
Output:
<span class="strikeuemstrong">four styles</span>
Finally getting the right output, after I fixed the ordering issue. Thank you for the help.
This is not a straight forward question to answer. I'll describe how I'd write the algorithm to do this, and include some pseudo code to help.
I'd get my parent tag. I'll assume you want to do this for all "p" tags
I'd iterate over my children tags, taking the tag name and appending it into a class name
I'd recursively iterate children until I get my appended tag name
Pseudo-code. Please excuse any typos, as I'm typing this on the fly.
public string GetClassName(Node n)
{
var ret = n.TagName;
foreach(var child in n.ChildNodes)
{
ret += GetClassName(child);
}
return ret;
}
foreach(var p in paragraphs)
{
foreach(var child in p.ChildNodes)
{
var span = new Span();
span.InnerText = child.InnerText; // strip all tags, just take the inner text
span.ClassName = GetClassName(child);
child.ReplaceWith(span); // note: if you do this with a FOREACH and not a for loop, it'll blow up C# for modifying the collection while iterating. Use for loops. if you're going to do "active" replacement like in this pseudo code
}
}
I'd be happy to modify my answer once I get more context. Please review what I'm suggesting and comment on it with more context if you need me to refine my suggestion. If not, I hope this gets you what you need :)

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).