There is an xml file (from approx):

<?xml version="1.0" encoding="utf-8"?> <servers version="1"> <server> <serverName>Shanghai_VPN</serverName> <serverIP>127.0.0.1</serverIP> </server> <server> <serverName>Beijing_VPN</serverName> <serverIP>127.0.0.2</serverIP> </server> 

 package main import ( "encoding/xml" "fmt" "io/ioutil" "os" ) type Recurlyservers struct { Svs []server `xml:"server"` } type server struct { ServerIP string `xml:"serverIP"` } func main() { file, err := os.Open("go.xml") // For read access. if err != nil { fmt.Printf("error: %v", err) return } defer file.Close() data, err := ioutil.ReadAll(file) if err != nil { fmt.Printf("error: %v", err) return } v := Recurlyservers{} err = xml.Unmarshal(data, &v) if err != nil { fmt.Printf("error: %v", err) return } for _, v := range v.Svs { fmt.Println(":::", v.ServerIP) } } 

How can I write something in this tag?

  • 1. i.e. Do you need to replace <serverIP> 127.0.0.1 </ serverIP> with <serverIP> something else </ serverIP> for any one serverName, and do not touch the rest of the records? 2. What is the context of the task - for example, sometimes it is simpler and safer (from the point of view of maintaining the structure of the document) to work simply with strings. For example, find the desired item in rows and change it, and do not use xml parsers at all. - rekby
  • Well yes. For example: There is a record of such ip: <serverIP> 127.0.0.1 </ serverIP> I need to find a tag with this content and change it to something else, and now I can’t find information like me without unloading the whole structure, find and replace this value. If you throw an example, I will be very grateful. - Oma
  • No, I wonder if it is possible in the xml file without uploading it all to the program to change the field values ​​?? - Oma
  • Not overwriting the entire file will only work in the particular case - when your old and new values ​​are equal in length. Otherwise, the entire file (or its tail) will have to be rewritten. A simplified example on the lines can be found here play.golang.org/p/eaLFSJg8y_ if you have big xml (gigabytes for example) - you can do something similar, but by searching right in the process of reading, without loading all xml into memory at once. This approach will be faster than any xml parser and will definitely not spoil the rest of the document structure. - rekby
  • For add. protection you can still find the end of the piece through strings.Index (subXml, "</ server>") and work only with it - so as not to spoil the neighboring element if suddenly the serverIP does not appear in the current one. - rekby

1 answer 1

In your case, you will have to fully describe the xml message in the structures, otherwise you will lose nodes in the resulting xml-le:

 package main import ( "encoding/xml" "fmt" ) type Servers struct { XMLName xml.Name `xml:"servers"` Version int `xml:"version,attr"` Items []Server `xml:"server"` } type Server struct { ServerName string `xml:"serverName"` ServerIP string `xml:"serverIP"` } func main() { data := ` <servers version="1"> <server> <serverName>Shanghai_VPN</serverName> <serverIP>127.0.0.1</serverIP> </server> <server> <serverName>Beijing_VPN</serverName> <serverIP>127.0.0.2</serverIP> </server> </servers>` servers := Servers{ Items: []Server{}, } _ = xml.Unmarshal([]byte(data), &servers) for i := range servers.Items { fmt.Printf("%#v\n", servers.Items[i]) // Output 1 } for i := range servers.Items { servers.Items[i].ServerIP = fmt.Sprintf("test - %d", i) } resultXml, _ := xml.Marshal(servers) fmt.Print(string(resultXml)) // Output 2 } 

Output 1:

 main.Server{ServerName:"Shanghai_VPN", ServerIP:"127.0.0.1"} main.Server{ServerName:"Beijing_VPN", ServerIP:"127.0.0.2"} 

Output 2:

 <servers version="1"><server><serverName>Shanghai_VPN</serverName><serverIP>test - 0</serverIP></server><server><serverName>Beijing_VPN</serverName><serverIP>test - 1</serverIP></server></servers>