How to change a value in a xml file?

  1. 5 weeks ago
    Edited 5 weeks ago

    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?

  2. Beatrix W

    Nov 5 Pre-Release Testers Europe (Germany)
    Edited 5 weeks ago
    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.

  3. Paul L

    Nov 5 Xojo Inc http://docs.xojo.com

    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:

    Dim xml As New XmlDocument
    xml.LoadXml(kXML)
    
    // Get <DeviceInfo>
    Dim deviceInfo As XmlNode
    // xml.Firstchild is <Monitor> and its FirstChild is <DeviceInfo>
    deviceInfo = xml.FirstChild.FirstChild
    
    // Get <HostName>
    // This is the 2nd (0-based so use 1) child of <DeviceInfo>
    Dim hostName As XmlNode
    hostName = deviceInfo.Child(1)
    
    // Get value for <HostName>'s child which is OV
    Dim hostNameValue As String = hostName.FirstChild.Value
    
    // Change value for <HostName>'s child
    hostName.FirstChild.Value = "OV02"
    
    // The updated XML which you can use, save, etc.
    Dim newXML As String = xml.ToString

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

    Dim xml As New XmlDocument
    xml.LoadXml(kXML)
    
    // Search entire XML document for anything that contains <HostName> and
    // get the results back as a list.
    Dim hostNames As XmlNodeList
    hostNames = xml.Xql("//HostName")
    
    If hostNames.Length >= 0 Then
      // At least one <HostName> was found so change the first one's value
      // Change value for <HostName>
      hostNames.Item(0).FirstChild.Value = "OV02"
    End If
    
    Dim newXML As String = xml.ToString

    For reference:

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

  5. @Beatrix W 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.

    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?

    @Paul L 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:

    Dim xml As New XmlDocument
    xml.LoadXml(kXML)
    
    // Get <DeviceInfo>
    Dim deviceInfo As XmlNode
    // xml.Firstchild is <Monitor> and its FirstChild is <DeviceInfo>
    deviceInfo = xml.FirstChild.FirstChild
    
    // Get <HostName>
    // This is the 2nd (0-based so use 1) child of <DeviceInfo>
    Dim hostName As XmlNode
    hostName = deviceInfo.Child(1)
    
    // Get value for <HostName>'s child which is OV
    Dim hostNameValue As String = hostName.FirstChild.Value
    
    // Change value for <HostName>'s child
    hostName.FirstChild.Value = "OV02"
    
    // The updated XML which you can use, save, etc.
    Dim newXML As String = xml.ToString

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

    Dim xml As New XmlDocument
    xml.LoadXml(kXML)
    
    // Search entire XML document for anything that contains <HostName> and
    // get the results back as a list.
    Dim hostNames As XmlNodeList
    hostNames = xml.Xql("//HostName")
    
    If hostNames.Length >= 0 Then
      // At least one <HostName> was found so change the first one's value
      // Change value for <HostName>
      hostNames.Item(0).FirstChild.Value = "OV02"
    End If
    
    Dim newXML As String = xml.ToString

    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

  6. Alberto D

    Nov 6 Pre-Release Testers, Xojo Pro

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

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

    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

    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?

  8. Alberto D

    Nov 6 Pre-Release Testers, Xojo Pro

    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"
  9. Edited 5 weeks ago

    @Alberto D;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?

  10. Alberto D

    Nov 6 Pre-Release Testers, Xojo Pro
    Edited 5 weeks ago

    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.

  11. Paul L

    Nov 6 Xojo Inc http://docs.xojo.com

    @H S I also don't know what is really different between my code and the given solution. Both give the same output.

    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.

    @H S Am I not just forgetting a savexml command or something?

    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:

    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

    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 .

  12. @Alberto D;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.

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

    I think I'm on the right path.

  13. Alberto D

    Nov 6 Pre-Release Testers, Xojo Pro

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

  14. Paul L

    Nov 6 Xojo Inc http://docs.xojo.com

    @Alberto D;Poo 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.

or Sign Up to reply!