Help chaning value of tag inside an XML string

We have an ASP application with a MS SQL 2008 DB.
In one of the tables we save an XML string which has several tags and values saved in it. One of the tags is the "FieldReadOnly", inside we always save the value to be 'false'. Which is OK, we need it to be that way.
But in this particular page we need to update the value to 'true' for ALL tags inside the string, the page will read the string "strXML", then we need a routine that will change the string into the exact same code BUT with the value of FieldReadOnly changed to 'true'. And that should be called strXML2.

We then will use this string to send it to a web service. We have all the code BUT the routine to change the value from false to true, and this is where we need help. Below are examples of the two strings as they should look like.

1. We read the first string

    strXML = strXML & "<Field><FieldName>" & a(c) & "</FieldName><FieldValue>" & field & "</FieldValue><FieldReadOnly>false</FieldReadOnly><FieldVisibility>1</FieldVisibility><FieldRequired>false</FieldRequired><FieldFormat></FieldFormat><FieldMask>false</FieldMask><FieldCalcOverride>false</FieldCalcOverride><HiddenField>false</HiddenField></Field>"    

Open in new window

         
                 
2. We need to run the routing to change this:

 
<FieldReadOnly>false</FieldReadOnly>

Open in new window


into this:

 
<FieldReadOnly>true</FieldReadOnly>

Open in new window


On every tag found in the string. Then save that in a new string as the one below:

    strXML2 = strXML2 & "<Field><FieldName>" & a(c) & "</FieldName><FieldValue>" & field & "</FieldValue><FieldReadOnly>true</FieldReadOnly><FieldVisibility>1</FieldVisibility><FieldRequired>false</FieldRequired><FieldFormat></FieldFormat><FieldMask>false</FieldMask><FieldCalcOverride>false</FieldCalcOverride><HiddenField>false</HiddenField></Field>"     

Open in new window

LVL 1
AleksAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Athar SyedCommented:
If your table columns are actually the tag names, then you can simply create the xml using the select query

SELECT Col1, Col2, Col3, 'false' AS [FieldReadOnly]
FROM table(NOLOCK) FOR XML Auto

Open in new window

0
AleksAuthor Commented:
They aren't. We need to use the first xml as our source
0
Athar SyedCommented:
In that case it a matter of FIND & REPLACE in a string of XML.

Dim strXML As String = "blah_blah blahblah...blah<FieldReadOnly>false</FieldReadOnly>blahblah some more blah and more blah.."
Const BEGIN_tag As String = "<FieldReadOnly>"
Const END_tag As String = "</FieldReadOnly>"
Dim startPos As Integer = strXML.IndexOf(BEGIN_tag)
Dim endPos As Integer = strXML.IndexOf(END_tag)
Dim strXML2 As String = String.Empty

' everything from start fill start position (including the starting tag itself)
strXML2 = strXML.Substring(0, startPos + BEGIN_tag.Length)
strXML2 = strXML2 & "true"
' whatever is left after (and including the end tag)
strXML2 = strXML2 & strXML.Substring(endPos, strXML2.Length - endPos)

Open in new window

0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

AleksAuthor Commented:
Thanks. Will give this a try. I assume it works on any xml string that has those tags cuz they are all different. And they all have many tags. Like in the example.
I'll confirm later today.
0
Athar SyedCommented:
You can wrap it up in a function and call the function for whatever tag you need

' function Declaration
Public Function ReplaceTagValue(xmlData As String, tagName As String, NewValue As String) As String
    Dim startTagName As String = "<" & tagName & ">"
    Dim endTagName As String = "</" & tagName & ">"
    Dim startPos As Integer = xmlData.IndexOf(startTagName)
    Dim endPos As Integer = xmlData.IndexOf(endTagName)

    If startPos < 0 OrElse endPos < 0 Then
        ' Start or End tag not found. Return the whole thing as it is
        Return xmlData
    End If

    dim newXml As String = xmlData.SubString(0, startPos + startTagName.Length)
    newXml += newValue
    newXml += xmlData.SubString(endPos, xmlData.Length - endPos)

    return newXml
End Function

' Implementing the wrapped function
xmlStr = ReplaceTagValue(xmlStr, "FieldReadOnly", "true")
xmlStr = ReplaceTagValue(xmlStr, "IceCreamFlavor", "Strawberry Ripple")

Open in new window

0
AleksAuthor Commented:
There was a syntax error in the function. But we fixed it. The code below works but the problem is that it changes only the first tag to 'true', there are many 'fieldreadonly' tags in the string and all of them need to be updated.
So .. the function requires further tweaking .. can you help ?

Just in case, we are using Classic ASP.

Our code as it stands.

' function Declaration
Public Function ReplaceTagValue(xmlData, tagName, NewValue)
    Dim startTagName 
  startTagName = "<" & tagName & ">"
    Dim endTagName 
  endTagName= "</" & tagName & ">"
    Dim startPos 
  startPos= xmlData.IndexOf(startTagName)
    Dim endPos 
  endPos= xmlData.IndexOf(endTagName)

    If startPos < 0 Or endPos < 0 Then
        ' Start or End tag not found. Return the whole thing as it is
        Return xmlData
    End If

    dim newXml 
  newXml = xmlData.SubString(0, startPos + startTagName.Length)
    newXml = newXML + newValue
    newXml = newXML + xmlData.SubString(endPos, xmlData.Length - endPos)

    return newXml
End Function  
  
  Dim strXML2
  strXML2 = ReplaceTagValue(strXML,"FieldReadOnly","true")

Open in new window

0
AleksAuthor Commented:
Ok, Im trying something else after reading about nodes and DOM in XML:

function myFunction(xml)
	Set xmlDoc = CreateObject("Microsoft.XMLDOM")
	xmlDoc.async = False
	xmlDoc.LoadXml(xml) 

    dim x, i, xmlDoc 
    set x = xmlDoc.selectNodes("fieldreadonly")
     for i = 0 to i < x.length
         x(i).childNodes(0).text = "true"
	 next
	return xmlDoc
End Function

Open in new window


Sadly, it does not work, im getting the following error:

Microsoft VBScript runtime error '800a01a8'
Object required: 'x(...)'
 file.asp, line 9
0
Athar SyedCommented:
Sorry for the delay was busy with work.

The reason you are seeing this error is because, there is nothing in the x. Also your FOR loop is incorrect. Try the below code

function myFunction(oldXmlFile,newXmlfile)
	Dim xmlDoc, xmlRoot, xmlNodes, xmlNode
	
	Set xmlDoc = CreateObject("Microsoft.XMLDOM")
	xmlDoc.Async = False
	xmlDoc.Load(oldXmlFile)
	
	xmlRoot = xmlDoc.DocumentElement
	
	' this is case-sensitive, so correct your search
	Set xNodes = xmlRoot.selectNodes("//myXmlRoot/Field/FieldReadOnly")
	' use a FOR EACH instead of a FOR
	For Each xNode In xNodes
		xNode.Text = "true"
	Next
	xDoc.Save(newXmlFile)
	' to return use the function name
	' However returning the xDoc gave me an error
	' myFunction = xDoc
End Function

Open in new window


The above will work for the below xml file
<?xml version="1.0" ?>
<myXmlRoot>
	<Field>
		<FieldName>name1</FieldName>
		<FieldValue>value1</FieldValue>
		<FieldReadOnly>false</FieldReadOnly>
		<FieldVisibility>1</FieldVisibility>
		<FieldRequired>false</FieldRequired>
		<FieldFormat/>
		<FieldMask>false</FieldMask>
		<FieldCalcOverride>false</FieldCalcOverride>
		<HiddenField>false</HiddenField>
	</Field>
	<Field>
		<FieldName>name2</FieldName>
		<FieldValue>value2</FieldValue>
		<FieldReadOnly>false</FieldReadOnly>
		<FieldVisibility>1</FieldVisibility>
		<FieldRequired>false</FieldRequired>
		<FieldFormat/>
		<FieldMask>false</FieldMask>
		<FieldCalcOverride>false</FieldCalcOverride>
		<HiddenField>false</HiddenField>
	</Field>
</myXmlRoot>

Open in new window

0
AleksAuthor Commented:
This looks great!!!!
I changed correcty the name of the parent field (Called "ParentField")

sadly, It shows an error on this line:
      xmlRoot = xmlDoc.DocumentElement

Error is:
Microsoft VBScript runtime error '800a005b'
Object variable not set
0
Athar SyedCommented:
Make sure your entire XPath is correct. If possible post up a bit of your XML data, about 2-3 records as it is in the actual file. Might be able to help better.
0
AleksAuthor Commented:
XML sring is Extremelly long... but with this you get an Idea

<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<ParentField>
   <Field>
     <FieldName>name1</FieldName>
     <FieldValue>value1</FieldValue>
     <FieldReadOnly>false</FieldReadOnly>
     <FieldVisibility>1</FieldVisibility>
     <FieldRequired>false</FieldRequired>
     <FieldFormat></FieldFormat>
     <FieldMask>false</FieldMask>
     <FieldCalcOverride>false</FieldCalcOverride>
      <HiddenField>false</HiddenField>
   </Field>
   <Field>
     <FieldName>name2</FieldName>
     <FieldValue>value2</FieldValue>
     <FieldReadOnly>false</FieldReadOnly>
     <FieldVisibility>1</FieldVisibility>
     <FieldRequired>false</FieldRequired>
     <FieldFormat></FieldFormat>
     <FieldMask>false</FieldMask>
     <FieldCalcOverride>false</FieldCalcOverride>
      <HiddenField>false</HiddenField>
   </Field>
</ParentField>
0
Athar SyedCommented:
Great. My bad. I had tested before on VBScript (sample.vbs) and it seems not all on VBScript works on classic ASP.

The below code should work fine, as I tested on a web server using ASP file. It will print out the modified XML itself.

<%@ Language = VBScript %>
<%
'Option Explicit

Response.ContentType = "text/xml"

Function myFunction(xmlFilename)
	Dim xDoc, xRoot, xNodes, xNode
	
	Set xDoc = CreateObject("Microsoft.XMLDOM")
	xDoc.Async = "False"
	xDoc.Load(xmlFilename)
	
	If xDoc Is Nothing Then
		Response.Write("Error opening XML file")
		Exit Function
	End If
	
	Set xNodes = xDoc.SelectNodes("//ParentField/Field/FieldReadOnly")
	If xNodes Is Nothing Then
		Response.Write("FieldReadOnly node does not exist in the document.")
		Exit Function
	End If
	
	For Each xNode In xNodes
		xNode.Text = "true"
	Next

	Response.Write(xDoc.xml)
End Function

myFunction(Server.MapPath(".") & "/sample.xml")
%>

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
AleksAuthor Commented:
Im really sorry to keep bothering you (classic ASP is a pain for me...)
What if instead of printing I would like the function to return the XML as a string again?

Tried
RETURN xDoc.xml

But it did not work (I assume its becausexDoc.xml is an xml instead of a string)
0
Athar SyedCommented:
Classic ASP is based on the old Visual Basic. You don't have a Return statement in VB. You have to use the function_name = return_value

myFunction = xDoc.xml

Open in new window


Another fun fact, in XmlDocument, you use
XmlDocument.Load(xmlFile) to load an XML file
and
XmlDocument.LoadXml(xmlString) to load an XML string
0
AleksAuthor Commented:
Excellent Follow up, thank you!!!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.