How to change a value in a xml file?

Hi,

I would like to change the hostname value into OV02 in the following xml file example:

<Monitor>
	<DeviceInfo>
		<DeviceName>UNIT</DeviceName>
		<HostName>OV</HostName>
		<ID>862462032347916</ID>
		<FwVer>v1.10</FwVer>
		<MnfInfo>myunit.example</MnfInfo>
	</DeviceInfo>
</Monitor>

I can read the xml file and the value, but how can I change the value. I’ve tried three whole evenings. Maybe it is something really easy, but I can’t figure it out.

Could someone give me some advise?

xml = Replace(xml, "<HostName>OV</HostName>", "<HostName>OV02</HostName>")

If your change is really simple, then you can use a simple solution like my code above. If you need a more complex change or the xml changes then you have to find a different solution.

First you want to make sure you XML is really XML. So it needs to look like this:

<?xml version="1.0" encoding="UTF-8"?> <Monitor> <DeviceInfo> <DeviceName>UNIT</DeviceName> <HostName>OV</HostName> <ID>862462032347916</ID> <FwVer>v1.10</FwVer> <MnfInfo>myunit.example</MnfInfo> </DeviceInfo> </Monitor>

I put the above in a constant called kXML.

Then you can parse it to get the XmlNode that points to what you want to change. One way is to directly refer to it like this:

[code]Dim xml As New XmlDocument
xml.LoadXml(kXML)

// Get
Dim deviceInfo As XmlNode
// xml.Firstchild is and its FirstChild is
deviceInfo = xml.FirstChild.FirstChild

// Get
// This is the 2nd (0-based so use 1) child of
Dim hostName As XmlNode
hostName = deviceInfo.Child(1)

// Get value for 's child which is OV
Dim hostNameValue As String = hostName.FirstChild.Value

// Change value for 's child
hostName.FirstChild.Value = “OV02”

// The updated XML which you can use, save, etc.
Dim newXML As String = xml.ToString
[/code]

Alternatively you could search directly for the node you want and then change it. You would do that using Xql:

[code]Dim xml As New XmlDocument
xml.LoadXml(kXML)

// Search entire XML document for anything that contains and
// get the results back as a list.
Dim hostNames As XmlNodeList
hostNames = xml.Xql("//HostName")

If hostNames.Length >= 0 Then
// At least one was found so change the first one’s value
// Change value for
hostNames.Item(0).FirstChild.Value = “OV02”
End If

Dim newXML As String = xml.ToString[/code]

For reference:

Thanks both a lot.

Tonight I will try the given solutions.

I have to say that the xml file I have is a bit more complex, but I think I have a better understanding now how it works.

I will let you know what has worked for me.

[quote=412946:@Beatrix Willius]xml = Replace(xml, "<HostName>OV</HostName>", "<HostName>OV02</HostName>")

If your change is really simple, then you can use a simple solution like my code above. If you need a more complex change or the xml changes then you have to find a different solution.[/quote]

I’ve tried your solution, but when I want to run the program it gives me an error:
"There is more than one item with this name and it’s not clear to which this refers to

What am I doing wrong?

[quote=412948:@Paul Lefebvre]First you want to make sure you XML is really XML. So it needs to look like this:

<?xml version="1.0" encoding="UTF-8"?> <Monitor> <DeviceInfo> <DeviceName>UNIT</DeviceName> <HostName>OV</HostName> <ID>862462032347916</ID> <FwVer>v1.10</FwVer> <MnfInfo>myunit.example</MnfInfo> </DeviceInfo> </Monitor>

I put the above in a constant called kXML.

Then you can parse it to get the XmlNode that points to what you want to change. One way is to directly refer to it like this:

[code]Dim xml As New XmlDocument
xml.LoadXml(kXML)

// Get
Dim deviceInfo As XmlNode
// xml.Firstchild is and its FirstChild is
deviceInfo = xml.FirstChild.FirstChild

// Get
// This is the 2nd (0-based so use 1) child of
Dim hostName As XmlNode
hostName = deviceInfo.Child(1)

// Get value for 's child which is OV
Dim hostNameValue As String = hostName.FirstChild.Value

// Change value for 's child
hostName.FirstChild.Value = “OV02”

// The updated XML which you can use, save, etc.
Dim newXML As String = xml.ToString
[/code]

Alternatively you could search directly for the node you want and then change it. You would do that using Xql:

[code]Dim xml As New XmlDocument
xml.LoadXml(kXML)

// Search entire XML document for anything that contains and
// get the results back as a list.
Dim hostNames As XmlNodeList
hostNames = xml.Xql("//HostName")

If hostNames.Length >= 0 Then
// At least one was found so change the first one’s value
// Change value for
hostNames.Item(0).FirstChild.Value = “OV02”
End If

Dim newXML As String = xml.ToString[/code]

For reference:

OK. I’ve tried the first solution you gave me, but with no luck. I will give a more direct example on something I’m working on

Is hard to know what is wrong without seeing your code.

I can guess, for example, that Replace needs xml to be String and maybe you Dim xml As New xmldocument and loaded the xml to it. So I think is important to show the code you are using (or a simpler version that behaves just the same).

This is the one of the 100 xml files I’m working with. They all look the same only they have different information like the name for example.

What I want is to change the value of DI1 if necessary. Value can be “OPEN” or “CLOSE”. In this example the value is “CLOSE”.

<?xml version="1.0" encoding="utf-8"?> <Monitor> <DeviceInfo> <DeviceName>OV02</DeviceName> <HostName>DEVICE</HostName> <ID>10</ID> <FwVer>v1.10</FwVer> <MnfInfo>www.example.cc</MnfInfo> </DeviceInfo> <S> <S1> <description>Sensor1</description> <id>FFFFFFFFFFFF</id> <item1> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item1> <item2> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item2> </S1> <S2> <description>Sensor2</description> <id>FFFFFFFFFFFF</id> <item1> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item1> <item2> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item2> </S2> <S3> <description>Sensor3</description> <id>FFFFFFFFFFFF</id> <item1> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item1> <item2> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item2> </S3> <S4> <description>Sensor4</description> <id>FFFFFFFFFFFF</id> <item1> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item1> <item2> <value>---</value> <unit>---</unit> <alarm>0</alarm> </item2> </S4> </S> <AI> <AI1> <description>Analog In1</description> <value>0.00</value> <unit>VDC</unit> <multiplier>1.000</multiplier> <offset>0.000</offset> <alarm>0</alarm> </AI1> <AI2> <description>Analog In2</description> <value>0.00</value> <unit>VDC</unit> <multiplier>1.000</multiplier> <offset>0.000</offset> <alarm>0</alarm> </AI2> </AI> <DI> <DI1> <description>Digital In1</description> <value>CLOSE</value> <valuebin>1</valuebin> <alarm>0</alarm> </DI1> <DI2> <description>Digital In2</description> <value>O(nc)</value> <valuebin>1</valuebin> <alarm>0</alarm> </DI2> </DI> <R> <R1> <description>R1=LIGHT_OFF</description> <value></value> <valuebin>1</valuebin> </R1> <R2> <description>R2=LIGHT_OFF</description> <value></value> <valuebin>0</valuebin> </R2> </R> <HTTPPush> <Key>00:00:00:00:00:00</Key> <PushPeriod>60</PushPeriod> </HTTPPush> <hwerr>0</hwerr> <Alarmed>0</Alarmed> <Time> <Date>24.07.2017</Date> <Time>01:58:23</Time> </Time> </Monitor>

My code at the moment:

[code]Sub ChangeState(s As String)
Dim f As FolderItem = SpecialFolder.Desktop.Child(“OV02.xml”)

Dim xml As New XmlDocument
xml.LoadXml(f)

Dim xAttrSignal As XmlNode
xAttrSignal = xml.Child(0).Child(3).Child(0).Child(1).Child(0)

Dim xSignal As String = xAttrSignal.Value

If xSignal <> s Then
If xSignal = “OPEN” Then xSignal = “CLOSE” Else xSignal = “OPEN”
Dim NewXML As String = xml.ToString
End If

End Sub[/code]

With a button I give the “s as string” the word “OPEN”. With DIM newXML As String = xml.ToString it will not change my xml file.

Or is it not possible to change a value in a xml file?

Change your code from:

If xSignal = "OPEN" Then xSignal = "CLOSE" Else xSignal = "OPEN"

to:

If xSignal = "OPEN" Then xAttrSignal.Value = "CLOSE" Else xAttrSignal.Value = "OPEN"

[quote=413041:@Alberto De Poo]Change your code from:

If xSignal = "OPEN" Then xSignal = "CLOSE" Else xSignal = "OPEN"

to:

If xSignal = "OPEN" Then xAttrSignal.Value = "CLOSE" Else xAttrSignal.Value = "OPEN"

It will not change the xml file Di1 value when I change the code.

Am I not just forgetting a savexml command or something?

xml is defined as XmlDocument, you loaded OV02.xml from your computer. With the code change I point out, xml is updated.

You don’t show the code needed to put the xml back to OV02.xml file, so I don’t know if you are writing back the changed xml to the file.

If you don’t have SaveXML then OV02.xml file will not change.

They definitely do not give the same output. You need to make Alberto’s change because otherwise you’re only changing the value in the xSignal String variable and not in the XML itself.

You’ll also need to save the XML back to a file. Changing the copy in memory does not affect the file on the drive.

You can save it using a TextOutputStream. So the full code for your method would look like this:

[code]Public Sub ChangeState(s As String)
Dim f As FolderItem = SpecialFolder.Desktop.Child(“OV02.xml”)

Dim xml As New XmlDocument
xml.LoadXml(f)

Dim xAttrSignal As XmlNode
xAttrSignal = xml.Child(0).Child(3).Child(0).Child(1).Child(0)

Dim xSignal As String = xAttrSignal.Value

If xSignal <> s Then
If xSignal = “OPEN” Then xAttrSignal.Value = “CLOSE” Else xAttrSignal.Value = “OPEN”
Dim newXML As String = xml.ToString

// Save the XML file back to the file
Dim output As TextOutputStream = TextOutputStream.Create(f)
output.Write(newXML)
output.Close

End If

End Sub
[/code]

The newly output XML will not be formatted, however. If you want to format it you can use the technique described in this blog post: Formatting Your XML.

[quote=413049:@Alberto De Poo]xml is defined as XmlDocument, you loaded OV02.xml from your computer. With the code change I point out, xml is updated.

You don’t show the code needed to put the xml back to OV02.xml file, so I don’t know if you are writing back the changed xml to the file.

If you don’t have SaveXML then OV02.xml file will not change.[/quote]

I figured that I was forgetting the code needed to put the xml back to OV02.xml. So there was no code. Thanks for clearing that up :slight_smile:

I think I’m on the right path.

@Paul Lefebvre why use TextOutputStream and not SaveXML? I’m reading the docs but I can’t find why use one over the other.

Hah! Because I forgot about XmlDocument.SaveXML. That would be a better choice – less code, after all.