Creating an array from values in XML - asp-classic

I want to get values from an XML file. How can I make array of the values in m1, m2 and m3?. How can do this?
Here is the XML
<?xml version="1.0"?>
<language>
<menus>
<m1>HomePage</m1>
<m2>Contact</m2>
<m3>About Us</m3>
</menus>
</language>
Here's is the ASP code I have:
Set Menus = xmlDoc.selectNodes("//language/menus/*" )
MenuCount = Menus.length
For Each entry in Menus
If entry.tagName = "m1" Then
m1 = entry.text
elseif entry.tagName="m2" then
m2 = entry.text
elseif entry.tagName="m3" then
m3 = entry.text
End If
Next

First I'm compeled to point out that the xml structure presented is poor. If each element inside <menus> represents a menu then all elements ought to have the same tag name such as <menu>. The use of 1, 2 and 3 suffix indicates the xml designer is confused as to the difference between an identifier and a value. If those values are important (i.e., the ordinal position with in the document can not be relied on) then those values should be included as an attribute:-
<menus>
<menu position="1">HomePage</menu>
<menu position="2">Contact</menu>
<menu position="3">About Us</menu>
</menus>
As to putting them in an array your code seems pretty close but here you go.
Dim menuNodes: Set menuNodes= xmlDoc.selectNodes("/language/menus/menu" )
Redim menus(menuNodes.length - 1)
Dim i : i = 0
For Each menuNode in menu
menus(i) = menu.Text
i = i + 1
Next

Are you saying that your current ASP code doesn't work? One method for obtaining values from XML file and using them within ASP is shown below;
<%
Dim menuItems 'Array of menu items
Set objHTTP = Server.CreateObject("Msxml2.ServerXMLHTTP")
objHTTP.open "GET","http://yourxmlfeed.xml",false
objHTTP.send
XMLData = objHTTP.responseText
' this code takes the raw RSSFeed and loads it into an XML Object
Set xmlFeed = Server.CreateObject("MSXML2.DomDocument.4.0")
xmlFeed.async = false
xmlFeed.LoadXml(XMLData)
Set objHTTP = Nothing
Set objItems = xmlFeed.getElementsByTagName("menus")
Set xmlFeed = Nothing
' loop over all the items in the XML Feed
For x = 0 to objItems.length - 1
Set objItem = objItems.item(x)
For Each objChild in objItem.childNodes
menuItems = menuItems & objChild.text & ","
Next
Next
response.write DeleteLastComma(menuItems) 'menuItems is your array of menu items
Function DeleteLastComma
...function to remove last comma off array
End Function
%>

Related

Read String Array Fom XML into VBA

I have the Following XML which is a result from a certain WEB-Service.
<?xml version="1.0" encoding="UTF-8"?>
-<ArrayOfString xmlns="http://tempuri.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>16/May/2016 - 20/May/2016</string>
<string>20/May/2016 - 23/May/2016</string>
<string>23/May/2016 - 27/May/2016</string>
<string>27/May/2016 - 30/May/2016</string>
</ArrayOfString>
I have the Following VBA Code to read the Above XML
strRet = PostWebservice(strUrlEBenefit, strSoapAction, strXml)
intPos1 = InStr(strRet, "<string>") + 8
intPos2 = InStr(strRet, "</string>")
If intPos1 > 11 And intPos2 > 0 Then
xmlresult = Mid(strRet, intPos1, intPos2 - intPos1)
End If
as a result I'm Getting "16/May/2016 - 20/May/2016" in xmlresult.
What I want to do is getting all the date values Between all the [string] tags.
Can you please guide me how can I achieve the result? I understand I need to read it into array but I don't know how and didn't saw any useful tutorials for me(beginner in VBA and XML) to ref.
Read the xml-result which was returned from the web service into xml-document and use e.g. SelectSingleNode to select the node ArrayOfString. This node has namaspaces so you need to use namespaces in the xpath as well. Then just read all the child node texts e.g. into a collection here declared as result. HTH
Note: Add reference to Microsoft XML, v6.0 dll
Sub GetDateValues()
Dim xmlDocument As MSXML2.DOMDocument60
Dim xmlNamespaces As String
Dim arrayOfStringNode As IXMLDOMNode
Dim result As Collection
Dim xmlNode As IXMLDOMNode
Dim strRet As String
strRet = PostWebservice(strUrlEBenefit, strSoapAction, strXml)
Set xmlDocument = New DOMDocument60
If Not xmlDocument.LoadXML(strRet) Then
Err.Raise xmlDocument.parseError.ErrorCode, , xmlDocument.parseError.reason
End If
xmlNamespaces = "xmlns:myns='http://tempuri.org/'"
xmlDocument.setProperty "SelectionNamespaces", xmlNamespaces
Set arrayOfStringNode = xmlDocument.SelectSingleNode("/myns:ArrayOfString")
Set result = New Collection
For Each xmlNode In arrayOfStringNode.ChildNodes
result.Add xmlNode.Text
Next xmlNode
End Sub
I'm extrapolating using the answer from: 'dee', but reading in to an array with x number of columns. The reason for dNode below is because webservices often return auxiliary metadata at the same level as the actual value you want in your array. So you have to use SelectSingleNode at that point.
xmlDoc.SetProperty "SelectionNamespaces", xmlNamespaces
Set xmlNodes = xmlDoc.SelectNodes("/myns:.../...")
rws = xmlNodes.length
cols = var '# of columns from the request sent or extrapolate this code to count children of a single node at the level necessary
ReDim xay(1 To rws, 1 To cols)
For Each xNode In xmlNodes
r = r + 1
For c = 1 To UBound(xay, 2)
Set dNode = xNode.ChildNodes(c - 1)
Set dNode = dNode.SelectSingleNode("myns:THE_VALUE")
xay(r, c) = dNode.Text
Next c
Next xNode

Classic ASP xmlhhtp between < head> < /head> tags only

With classic ASP, i retrieve data from an another webpage with XMLHTTP, and save it to database.
private function gethttp(url)
Set strhttp=server.createobject("MSXML2.ServerXMLHTTP.6.0")
strhttp.Open "get",url,false
strhttp.send
gethttp=strhttp.responsetext
Set strhttp=Nothing
End function
url="http://www.noktadomains.com/buydomains/BodyBalance#BodyBalancing.com"
text=gethttp(url)
response.write(text)
is it possible only call source between < head>...< /head> tags?
Because the whole page is very large and takes too long to load, and i do not need the < html>...< /html> part of it !!
Thanks
Do you want to just extract the HEAD section out, like this?
(Add this code to the end of your function)
intStart = InStr(text, "<head>)
If intStart <> 0 Then
intStart = intStart + 6
intEnd = InStr(intStart, text, "</head>")
If intEnd <> 0 Then
text = Mid(text, intStart, intEnd - intStart)
End If
End If

No pages in Classic ASP site will load after entering some code on a single page

This site was working properly before I started encountering an error after entering some code. The code was not on the home page but none of the site pages will load now. I restarted the site in IIS and that did not help.
Here is the code that I entered:
'Prepare to parse XML
Set objXML = Server.CreateObject(Microsoft.XMLDOM)
'Set Asynchoronous = false
objXML.async = False
'Load the XML file.
'User Server.MapPath method is the XML is located in your site.
'Else you can use the absolute path.
objXML.Load (Server.MapPath(Products.xml))
'If there is any errors pasring the file the notify
If objXML.parseError.errorCode = 0 Then
'Response.Write(objXML.parseError.reason)
Else objXML.parseError.errorCode <> 0 Then
'Get ALL the Elements by the tag name product
Set products = objXML.getElementsByTagName(product)
Select Case iItemID
Case 1
aParameters = Array(products.item(0).childNodes(0).text, products.item(i).childNodes(2).text, products.item(i).childNodes(2).text)
Case 2
aParameters = Array(products.item(1).childNodes(0).text, products.item(i).childNodes(2).text, products.item(i).childNodes(2).text)
End Select
' Return array containing product info.
GetItemParameters = aParameters
End If
Running IIS in Windows 7 using classic ASP. Editing with Notepad++.
Here is the XML file:
<configuration>
<products>
<product>
<image>
<![CDATA[ /Images/Atlas Gloves.jpg ]]>
</image>
<name>
<![CDATA[ Atlas Nitrile Touch Gloves ]]>
</name>
<description>
<![CDATA[ Atlas Nitrile Touch is available in 6 vibrant colors, and is America’s #1 glove for the Lawn and Garden market. Atlas gloves have a breathable nylon back and are machine washable. Like a “second skin,” these gloves are the most comfortable! Atlas Nitrile gloves are the #1 gardening gloves. Atlas Nitrile gloves act like a "second skin" between the user and their work, offering full dexterity and grip. Atlas Nitrile Gloves are perfect for gardening, but their uses expand to so many places – the woodshop, the workshop, the workplace. ]]>
</description>
<size>
<![CDATA[ Small, Medium ]]>
</size>
<color>
<![CDATA[ Purple, Pink, Green, Orange ]]>
</color>
</product>
</products>
</configuration>
Lets start by getting the code in order:
First we'll create a little helper function which given a parent XML element and an XPath (can be simply a tagName of a child element) will return the text value of an element. In this case I have deliberately choosen to return null if the element isn't found but you could leave the return value empty if you prefer:
Function GetElemText(parentElem, path)
Dim elem: Set elem = parentElem.selectSingleNode(path)
If Not elem Is Nothing Then
GetElemText = elem.text
Else
GetElemText = null
End If
End Function
Now we'll create a little VBScript class which has a field for each of the product elements. This class has a LoadFromXml method which given an product xml element will extract the field values.
Class Product
Public Image
Public Name
Public Description
Public Size
Public Color
Public Sub LoadFromXml(prodElem)
Image = GetElemText(prodElem, "image")
Name = GetElemText(prodElem, "name")
Description = GetElemText(prodElem, "description")
Size = GetElemText(prodElem, "size")
Color = GetElemText(prodElem, "color")
End Sub
End Class
Finally we create a GetProduct function that given the index of a product will load return a Product class instance loaded with the appropriate product details.
Function GetProduct(productIndex)
Dim objXML: Set objXML = Server.CreateObject("MSXML2.DOMDocument.3.0")
objXML.async = False
objXML.setProperty "SelectionLanguage", "XPath"
objXML.Load Server.MapPath("Products.xml") ''# Assumes Products xml in same folder as this script
Dim elem: Set elem = objXML.documentElement.selectSingleNode("products/product[" & productIndex & "]")
If Not elem Is Nothing Then
Set GetProduct = new Product
GetProduct.LoadFromXml elem
Else
Set GetProduct = Nothing
End If
End Function
Note the use named elements eliminates the need for "magic numbers" the values of which you would either have to remember or place in constants and are very fragile. Also the use of XPath as the selection language and a more specific ProgID. All in all much more robust and in this case also working.
If your products xml remains fairly static over the life time of the application consider this variation of:
Function GetProduct(productIndex)
Dim objXML
If IsEmpty(Application.Contents("Products")) Then
Set objXML = Server.CreateObject("MSXML2.FreeThreadedDOMDocument.3.0")
objXML.async = False
objXML.setProperty "SelectionLanguage", "XPath"
Set Application.Contents("Products") = objXML
Else
Set objXML = Application.Contents("Products")
End If
objXML.Load Server.MapPath("Products.xml") ''# Assumes Products xml in same folder as this script
Dim elem: Set elem = objXML.documentElement.selectSingleNode("products/product[" & productIndex & "]")
If Not elem Is Nothing Then
Set GetProduct = new Product
GetProduct.LoadFromXml elem
Else
Set GetProduct = Nothing
End If
End Function
This loads the XML DOM into the application store saving the cost of reloading every time a product is needed.
One other change I would recommend, the reliance of know the ordinal position of a product element in order to retrieve it is quite fragile. Consider adding an id="1" attribute to the product element. It can then be retrieved with:
Dim elem: Set elem = objXML.documentElement.selectSingleNode("products/product[#id=""" & productIndex & """]")

Creating Dynamic Hotspots in an ASP.net imagemap

I need the ability to create a dynamic number of hotspots in an imagemap
the pseudo code for what I want to do is below:
Protected Sub AddHotSpot()
Dim r1 New RectangleHotSpot
For Each Item as datarow in dataset
r1.HotSpotMode = HotSpotMode.PostBack
r1.PostBackValue = "HotSpot 1"
r1.AlternateText = "HotSpot 1"
r1.Top = Item.Top
r1.Left = Item.Left
r1.Bottom = Item.Bottom
r1.Right = Item.Right
Next
think of r1 as some form of dynamic construct
Figured out how to perform this. I had to make the object above part of an array list then add each object to the array

System.OutOfMemoryException

I have a program written in asp.net with lucene.net. At first I create an index from 28000 documents.
Secondly I'm executing a search, but sometimes there is an error. (I think this error is thrown when there are many results)
The important part of code:
Dim hits As Hits = searcher.Search(query)
Dim results As Integer = hits.Length() 'ergebnisse (größe der hits)
'#####################
'####### RESULTS #####
'#####################
trefferanzahl = results
If (results > 0) Then
Dim i As Integer
Dim h As Integer = results - 1
ReDim array_results(h, 6) 'array zum speichern von den "feldern"
Dim cellX As New TableCell()
For i = 0 To results - 1 Step 1
Dim tmpdoc As Document = hits.Doc(i) ' HERE THE ERROR!
Dim score As Double = hits.Score(i)
MsgBox("2. Docname: " & hits.Doc(i).Get("title"))
array_results(i, 0) = tmpdoc.Get("title")
array_results(i, 0) += tmpdoc.Get("doc_typ")
array_results(i, 1) = tmpdoc.Get("pfad")
array_results(i, 2) = tmpdoc.Get("date_of_create")
array_results(i, 3) = tmpdoc.Get("last_change")
array_results(i, 4) = tmpdoc.Get("id")
array_results(i, 5) = tmpdoc.Get("doc_typ")
array_results(i, 6) = CStr(score)
Next
' Load this data only once.
ItemsGrid.DataSource = CreateDataSource()
ItemsGrid.DataBind()
Else
bool_Suchergebnis = False
End If
searcher.Close()
Thanks in advance
A good principle when performing searches accross very large collections is to limit the results that you are processing as soon as possible. I will assume that you are implementing paging in your grid. And lets assume that PageSize is 20.
What you need to do is make sure that you have access to the PageSize and the current PageNo within this method. Then use Linq accross the result set to Take(PageSize) and Skip (PageNo * PageSize). Then you will only have to process 20 records.
Then, you have two options. If you are binding directly to the array, you might be able to get away with empty items, but I am not sure, so you might have to place dummy items into the datasource array in all positions that won't be displayed. Not ideal, but certainly quicker than processing 1000s of Hits.
The second option is to bind only the 20 items to the grid, which will be quick, switch off paging on the grid as it will only show one page and then implement your own paging behaviour as you know the PageSize, and the current PageNo. This will take more work but it will perform a lot faster than the out-of-the-box gridview binding to a large datasource.
And it will help you solve your memory problem.

Resources