Solved

ASP classic script needed to read every single tag value and attribute

Posted on 2014-09-26
24
350 Views
Last Modified: 2014-09-30
I am using ASP classic with VBScript and would like to read all tag names, attributes and values of an XML file.

I have the following code example which I have started and would like a simple script to output everything starting from the <result> tag and everything within it.

Dim xmlstr, xmlObj, xmlList, xmlItem, Row, Details, detail

	xmlstr= "<?xml version=""1.0"" encoding=""UTF-8"" ?>" &_
			"<response uri=""/crm/private/xml/Leads/insertRecords"">" &_
			"  <result>" &_
			"	<row no=""3"">" &_
			"	  <success>" &_
			"       <code>2000</code>" &_
			"		<details>" &_
			"		  <FL val=""Id"">1240444000000100001</FL>" &_
			"		  <FL val=""Created Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Modified Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Created By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		  <FL val=""Modified By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		</details>" &_
			"	  </success>" &_
			"	</row>" &_
			"	<row no=""2"">" &_
			"	  <success>" &_
			"       <code>2000</code>" &_
			"		<details>" &_
			"		  <FL val=""Id"">1240444000000100002</FL>" &_
			"		  <FL val=""Created Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Modified Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Created By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		  <FL val=""Modified By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		</details>" &_
			"	  </success>" &_
			"	</row>" &_
			"	<row no=""1"">" &_
			"	  <success>" &_
			"       <code>2000</code>" &_
			"		<details>" &_
			"		  <FL val=""Id"">1240444000000100003</FL>" &_
			"		  <FL val=""Created Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Modified Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Created By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		  <FL val=""Modified By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		</details>" &_
			"	  </success>" &_
			"	</row>" &_
			"  </result>" &_
			"</response>"

	Set xmlObj = Server.CreateObject("Microsoft.XMLDOM")
	xmlObj.async = False
	xmlObj.setProperty "ServerHTTPRequest", True
	xmlObj.LoadXML(xmlstr)
	If xmlObj.parseError.errorCode <> 0 Then
		'### NOTHING
	End If
	
	Set xmlList = xmlObj.getElementsByTagName("result")
	
	' Scan through result tags but in this case there is only one
	For Each xmlItem In xmlList  
	
               ' What do I do now?
		
	Next
			
	Set xmlList = Nothing
	Set xmlObj = Nothing

Open in new window


So what I am looking for is an output like this:

row - no:1
   success
      code = 2000
      details
           FL - val:Id = 1240444000000100001
           FL - val:Created Time = 1240444000000100001

"
"
row - no:2
   success
      code = 2000
      details
           FL - val:Id = 1240444000000100002
           FL - val:Created Time = 2014-09-26 00:47:16

Etc..
0
Comment
Question by:mike99c
  • 15
  • 7
24 Comments
 
LVL 32

Assisted Solution

by:Big Monty
Big Monty earned 200 total points
Comment Utility
have a look at this tutorial, it'll show you how to loop through everything.

http://www.w3schools.com/dom/dom_nodes_access.asp

gimme a few minutes to come up with an example using your code
0
 
LVL 32

Expert Comment

by:Big Monty
Comment Utility
sorry, something came up that's going to require my attention for the rest of the day. Didn't want to leave you hanging, so here's something that'll get cyou a reference to each row. hopefully someone else comes along and can help finish up whatever questions you may have, otherwise I'll try to get to this later

add the following code to the section where you want to loop through the xml doc and parse everything out

Set itemList = xmlObj.SelectNodes("response/result")
 
For Each itemAttrib In itemList
    '   Response.Write itemAttrib.SelectNodes("response/result").getAttribute("row").text
       Response.Write itemAttrib.SelectSingleNode("row").text

Next

Open in new window

0
 

Author Comment

by:mike99c
Comment Utility
OK Big Monty appreciate your input I will give this a go.
0
 

Author Comment

by:mike99c
Comment Utility
I tried inserting the script and got the following output:
2000 1240444000000100001 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith

It seems to only output all the child tag values in the first row tag only. I had similar issues before and need to get all the other values too.
0
 

Author Comment

by:mike99c
Comment Utility
OK I have made some progress and managed to list the tags, values and attributes using the following code:

	Dim x, y, z, i, j
	For Each x in xmlObj.documentElement.childNodes
	
	    response.write x.nodename & "<br>"
		
		For Each y in x.childNodes

	        response.write " -- " & y.nodename & " no: " & y.GetAttribute("no") & " hasChildNodes: " & y.hasChildNodes & "<br>"

			For Each z in y.childNodes
	
				response.write " ---- " & z.nodename & " hasChildNodes: " & y.hasChildNodes & "<br>"

				For Each i in z.childNodes
		
					response.write " ------ " & i.nodename & " " & i.text & " hasChildNodes: " & i.hasChildNodes & "<br>"
					
					If i.nodename = "details" Then

						For Each j in i.childNodes
				
							response.write " -------- " & j.nodename & " - " & j.text  & " val: " & j.GetAttribute("val") & " hasChildNodes: " & j.hasChildNodes & "<br>"
						
						Next
					
					End if
				
				Next
			
			Next
		
		Next
		
	Next

Open in new window


The output is as follows:

result
-- row no: 3 hasChildNodes: True
---- success hasChildNodes: True
------ code 2000 hasChildNodes: True
------ details 1240444000000100001 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith hasChildNodes: True
-------- FL - 1240444000000100001 val: Id hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Created Time hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Modified Time hasChildNodes: True
-------- FL - John Smith val: Created By hasChildNodes: True
-------- FL - John Smith val: Modified By hasChildNodes: True
-- row no: 2 hasChildNodes: True
---- success hasChildNodes: True
------ code 2000 hasChildNodes: True
------ details 1240444000000100002 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith hasChildNodes: True
-------- FL - 1240444000000100002 val: Id hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Created Time hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Modified Time hasChildNodes: True
-------- FL - John Smith val: Created By hasChildNodes: True
-------- FL - John Smith val: Modified By hasChildNodes: True
-- row no: 1 hasChildNodes: True
---- success hasChildNodes: True
------ code 2000 hasChildNodes: True
------ details 1240444000000100003 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith hasChildNodes: True
-------- FL - 1240444000000100003 val: Id hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Created Time hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Modified Time hasChildNodes: True
-------- FL - John Smith val: Created By hasChildNodes: True
-------- FL - John Smith val: Modified By hasChildNodes: True

Open in new window


Now rather than close this task I would like help with something which I am confused about. I have called the property hasChildNodes and I was hoping this would return False if a tag does not contain anymore children. For example the <code> tag returns True for hasChildNodes but I was expecting it to return False. The same applies for the tag <FL>, surely this should also return False.

Among other things I do not for example want to output the text for tag <details> as it contains children.
0
 
LVL 32

Expert Comment

by:Big Monty
Comment Utility
the hasChildNodes property is a bit mis-leading, as it'll only return false if no text is present in the node, as any text that IS present is considered a separate node.

http://www.w3schools.com/dom/dom_nodes.asp

try taking out any of the text in between the FL tags, and you'll see the hasChildNodes property return false.
0
 

Author Comment

by:mike99c
Comment Utility
OK thanks, so how do I make the test work like I want? That is I need a test to check if a tag contains child tags hence:

<code>200</code>
Should return false

<details>
  <FL ..
</details>
Should return true.
0
 
LVL 32

Expert Comment

by:Big Monty
Comment Utility
when you're looping through the nodes, check the TEXT property of next node, if it is blank, it has no child nodes
0
 

Author Comment

by:mike99c
Comment Utility
Unfortunately that does not work because when I output the text property for the tag <details> I get:

1240444000000100001 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith

The text property seems to return the values of all the child tags.
0
 
LVL 32

Expert Comment

by:Big Monty
Comment Utility
Have a look at the link below, it makes use of the NOTHING keyword

http://forums.devx.com/showthread.php?3020-Quick-way-to-check-if-an-element-exists
0
 

Author Comment

by:mike99c
Comment Utility
Thanks Big Monty, however I am having problems assigning the node and get a run time error.

Here is the modified code:

	Set xmlObj = Server.CreateObject("Microsoft.XMLDOM")
	xmlObj.async = False
	xmlObj.setProperty "ServerHTTPRequest", True
	xmlObj.LoadXML(xmlstr)
	If xmlObj.parseError.errorCode <> 0 Then
		'### NOTHING
	End If
	
	Dim x, y, z, i, j, node
	For Each x in xmlObj.documentElement.childNodes
	
	    response.write x.nodename & "<br>"
		
		For Each y in x.childNodes

	        response.write " -- " & y.nodename & " no: " & y.GetAttribute("no") & " hasChildNodes: " & y.hasChildNodes() & "<br>"

			For Each z in y.childNodes
	
				response.write " ---- " & z.nodename & " hasChildNodes: " & y.hasChildNodes() & "<br>"

				For Each i in z.childNodes
		
					response.write " ------ " & i.nodename & " " & i.text & " hasChildNodes: " & i.hasChildNodes() & "<br>"
					
					node = xmlObj.selectSingleNode(i.nodename)
					
					If i.nodename = "details" Then

						For Each j in i.childNodes
				
							response.write " -------- " & j.nodename & " - " & j.text  & " val: " & j.GetAttribute("val") & " hasChildNodes: " & j.hasChildNodes() & "<br>"
						
						Next
					
					End if
				
				Next
			
			Next
		
		Next
		
	Next

Open in new window


Before I can do the check I added the following line:
node = xmlObj.selectSingleNode(i.nodename)

However i get  the following run time error:
Microsoft VBScript runtime error '800a005b'

Object variable not set
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:mike99c
Comment Utility
Oops my mistake, forgot to add "Set".
0
 

Author Comment

by:mike99c
Comment Utility
Ok I tried:
Set node = xmlObj.selectSingleNode(i.nodename)

I can confirm that this returns "nothing" for both < code> and <description>. I am quite amazed how difficult it is to identify something so simple.

Going to try getElementsbyTagName and look at the length as described in http://forums.devx.com/showthread.php?3020-Quick-way-to-check-if-an-element-exists.
0
 

Author Comment

by:mike99c
Comment Utility
Ok I tried the following:

Set nodes = xmlObj.selectNodes(i.nodename)
response.write " ------ " & i.nodename & " length: " & nodes.length & "<br>"

Open in new window


Unfortunately a length of zero is returned for tags <code> and <details>. Surely there must be a simple solution to this.
0
 
LVL 32

Expert Comment

by:Big Monty
Comment Utility
Can you post the latest version of your code, including the xml, and I'll have a look tonight if I get a chance? You're right, it shouldn't be this difficult :)
0
 

Author Comment

by:mike99c
Comment Utility
Ok here is the complete script in which I check single node, node length and first child and I cannot differentiate anything between a tag containing just data and one containing child tags.

Here is the full code:

Dim xmlstr, xmlObj, xmlList, x, y, z, i, j, node, nodes, fc

	xmlstr= "<?xml version=""1.0"" encoding=""UTF-8"" ?>" &_
			"<response uri=""/crm/private/xml/Leads/insertRecords"">" &_
			"  <result>" &_
			"	<row no=""3"">" &_
			"	  <success>" &_
			"       <code>2000</code>" &_
			"		<details>" &_
			"		  <FL val=""Id"">1240444000000100001</FL>" &_
			"		  <FL val=""Created Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Modified Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Created By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		  <FL val=""Modified By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		</details>" &_
			"	  </success>" &_
			"	</row>" &_
			"	<row no=""2"">" &_
			"	  <success>" &_
			"       <code>2000</code>" &_
			"		<details>" &_
			"		  <FL val=""Id"">1240444000000100002</FL>" &_
			"		  <FL val=""Created Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Modified Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Created By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		  <FL val=""Modified By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		</details>" &_
			"	  </success>" &_
			"	</row>" &_
			"	<row no=""1"">" &_
			"	  <success>" &_
			"       <code>2000</code>" &_
			"		<details>" &_
			"		  <FL val=""Id"">1240444000000100003</FL>" &_
			"		  <FL val=""Created Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Modified Time"">2014-09-26 00:47:16</FL>" &_
			"		  <FL val=""Created By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		  <FL val=""Modified By"">" &_
			"			<![CDATA[John Smith]]>" &_
			"		  </FL>" &_
			"		</details>" &_
			"	  </success>" &_
			"	</row>" &_
			"  </result>" &_
			"</response>"

	Set xmlObj = Server.CreateObject("Microsoft.XMLDOM")
	xmlObj.async = False
	xmlObj.setProperty "ServerHTTPRequest", True
	xmlObj.LoadXML(xmlstr)
	If xmlObj.parseError.errorCode <> 0 Then
		'### NOTHING
	End If
	
	For Each x in xmlObj.documentElement.childNodes
	
	    response.write x.nodename & "<br>"
		
		For Each y in x.childNodes

	        response.write " -- " & y.nodename & " no: " & y.GetAttribute("no") & " hasChildNodes: " & y.hasChildNodes() & "<br>"

			For Each z in y.childNodes
	
				response.write " ---- " & z.nodename & " hasChildNodes: " & y.hasChildNodes() & "<br>"

				For Each i in z.childNodes
		
					response.write " ------ " & i.nodename & " " & i.text & " hasChildNodes: " & i.hasChildNodes() & " nodeType: " & i.nodeType &  "<br>"
					
					Set node = xmlObj.selectSingleNode(i.nodename)
					If node is Nothing Then
					   response.write " ------ " & i.nodename & " is nothing<br>"
					Else
					   response.write " ------ " & i.nodename & " is NOT nothing<br>"
					End If
										
					Set nodes = xmlObj.selectNodes(i.nodename)
					response.write " ------ " & i.nodename & " length: " & nodes.length & "<br>"
					
					Set fc = xmlObj.documentElement.firstChild
					response.write " ------ " & i.nodename & " fc.nodeType: " & fc.nodeType & "<br>"
					
					If i.nodename = "details" Then

						For Each j in i.childNodes
				
							response.write " -------- " & j.nodename & " - " & j.text  & " val: " & j.GetAttribute("val") & " hasChildNodes: " & j.hasChildNodes() & "<br>"
						
						Next
					
					End if
				
				Next
			
			Next
		
		Next
		
	Next
	
	Set xmlList = Nothing
	Set xmlObj = Nothing

Open in new window


And here is the output:

result
-- row no: 3 hasChildNodes: True
---- success hasChildNodes: True
------ code 2000 hasChildNodes: True nodeType: 1
------ code is nothing
------ code length: 0
------ code fc.nodeType: 1
------ details 1240444000000100001 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith hasChildNodes: True nodeType: 1
------ details is nothing
------ details length: 0
------ details fc.nodeType: 1
-------- FL - 1240444000000100001 val: Id hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Created Time hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Modified Time hasChildNodes: True
-------- FL - John Smith val: Created By hasChildNodes: True
-------- FL - John Smith val: Modified By hasChildNodes: True
-- row no: 2 hasChildNodes: True
---- success hasChildNodes: True
------ code 2000 hasChildNodes: True nodeType: 1
------ code is nothing
------ code length: 0
------ code fc.nodeType: 1
------ details 1240444000000100002 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith hasChildNodes: True nodeType: 1
------ details is nothing
------ details length: 0
------ details fc.nodeType: 1
-------- FL - 1240444000000100002 val: Id hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Created Time hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Modified Time hasChildNodes: True
-------- FL - John Smith val: Created By hasChildNodes: True
-------- FL - John Smith val: Modified By hasChildNodes: True
-- row no: 1 hasChildNodes: True
---- success hasChildNodes: True
------ code 2000 hasChildNodes: True nodeType: 1
------ code is nothing
------ code length: 0
------ code fc.nodeType: 1
------ details 1240444000000100003 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith hasChildNodes: True nodeType: 1
------ details is nothing
------ details length: 0
------ details fc.nodeType: 1
-------- FL - 1240444000000100003 val: Id hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Created Time hasChildNodes: True
-------- FL - 2014-09-26 00:47:16 val: Modified Time hasChildNodes: True
-------- FL - John Smith val: Created By hasChildNodes: True
-------- FL - John Smith val: Modified By hasChildNodes: True

Open in new window

0
 

Author Comment

by:mike99c
Comment Utility
I think the first child may help but the following may not be correct:

Set fc = xmlObj.documentElement.firstChild

Instead of xmlObj I need to take it from the current node. I tried:

Set fc = i.documentElement.firstChild
Set fc = z.childNodes.documentElement.firstChild
Set fc = z.childNodes.firstChild

And all these flag errors.

Set fc = xmlObj.documentElement.firstChild
response.write " ------ " & i.nodename & " fc.nodeType: " & fc.nodeType & "<br>"
response.write " ------ " & i.nodename & " fc.text: " & fc.text & "<br>"
response.write " ------ " & i.nodename & " fc.tagName: " & fc.tagName & "<br>"

Open in new window


I know Set fc = xmlObj.documentElement.firstChild is not right because the tagName returned is result which is the top level tag.
0
 

Author Comment

by:mike99c
Comment Utility
Any takers? Will give it another hour before I close this down.
0
 
LVL 35

Accepted Solution

by:
Robert Schutt earned 300 total points
Comment Utility
I'm actually not really sure what your current issues are but I'll pick one out: as BigMonty explained, properties and methods of the XML Node class like childNodes, hasChildNodes() and firstChild also pertain to text nodes. If you want to determine whether a node has child elements (or child tags as you called it here) then you will need to check the node type of each of the childNodes for example with a function like this:
Function hasChildElements(n)
	Dim subnode
	For Each subnode In n.childNodes
		If subnode.nodeType = 1 Then ' Element
			hasChildElements = True
			Exit Function
		End If
	Next
	hasChildElements = False
End Function

Open in new window

Using that in your code for example:
response.write " ------ " & i.nodename & " " & i.text & " hasChildNodes: " & i.hasChildNodes() & " <b>hasChildElements: " & hasChildElements(i) & "</b> nodeType: " & i.nodeType &  "<br>"

Open in new window

In the output you will now see sometimes i.hasChildNodes being true while hasChildElements(i) is false, which means in your situation there is only text in the node (for example <code>).

Now it's not clear to me what you want next but you can use that function in an "if" statement and decide how to process further depending on this information. Or, maybe simpler, you can check for nodeType = 1 in the For Each loops.

Or, changing a bit of code you already have in there: you can search for any child element of the current node i with:
					Set node = i.selectSingleNode(".//*")
					If node is Nothing Then
					   response.write " ------ " & i.nodename & " 'any child element' is nothing<br>"
					Else
					   response.write " ------ " & i.nodename & " 'any child element' is NOT nothing<br>"
					End If

Open in new window

In the following output you can see these code changes give consistent results: where hasChildElements() returns false, the 'any child element' is nothing (for example <code>) and where hasChildElements() is true, the 'any child element' is NOT nothing (for example <details>). So you can use either of these methods.
...
-- row no: 1 hasChildNodes: True
---- success hasChildNodes: True
------ code 2000 hasChildNodes: True hasChildElements: False nodeType: 1
------ code 'any child element' is nothing
------ details 1240444000000100003 2014-09-26 00:47:16 2014-09-26 00:47:16 John Smith John Smith hasChildNodes: True hasChildElements: True nodeType: 1
------ details 'any child element' is NOT nothing
...

Open in new window

0
 

Author Comment

by:mike99c
Comment Utility
The check to see if a tag contains nested tags is achieved using:

Set node = i.selectSingleNode(".//*")

OR

hasChildElements(i)
0
 
LVL 32

Expert Comment

by:Big Monty
Comment Utility
why no split? i got you the majority of the way there I thought
0
 

Author Comment

by:mike99c
Comment Utility
Hi Big Monty, Apologies for this, I have asked Experts Exchange to reset the points awarded so I can award a split.
0
 

Author Comment

by:mike99c
Comment Utility
Thanks Robert. I know how to split points and have done so many times, it's just that on this occassion I should have split it with Big Monty.
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

This script will sweep a range of IP addresses (class c only, 255.255.255.0) and report to a log the version of office installed. What it does: 1.)      Creates log file in the directory the script is run from (if it doesn't already exist) 2.)      Sweep…
Many times as a report developer I've been asked to display normalized data such as three rows with values Jack, Joe, and Bob as a single comma-separated string such as 'Jack, Joe, Bob', and vice versa.  Here's how to do it. 
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now