NewMapXmlSeq process instructions
Closed this issue · 8 comments
hi,
I'm dealing with some XML files that have <?xml version="1.0" encoding="utf-8"?>
at top of the file by using the NewMapXmlSeq
cause I want to preserve the format and some comments in the file.
But I could only get the result map[#procinst:map[#target:xml #inst:version="1.0" encoding="utf-8"]]
,
and the returned error is no root key
As you mentioned in the doc:
comments, directives, and procinsts that are NOT part of a document with a root key will be returned as
map[string]interface{} and the error value 'NoRoot'.
How can I get the whole map of the XML file?
I thought it's quite common that <?xml version="1.0" encoding="utf-8"?>
not belong to any root
If you want the whole file in a single map[string]interface{} do something like:
fh, err := os.Open(file) if err != nil { // handle error } defer fh.Close() m := make(map[string]interface{}) var v map[string]interface{} for { v, err = mxj.NewMapXmlSeqReader(fh) for key, val := range v { m[key] = val } if err != nil { if err == io.EOF { break; } if err != mxj.NoRoot { // handle error } } } // do something with 'm'
Of course, if your io.Reader has multiple docs with the same root tag, you'll only get the last one read.
I got the same result using above code. I also simplified the XML file.
The loop break at the second round met the EOF so I could only get the map[#procinst:map[#target:xml #inst:version="1.0" encoding="utf-8"]]
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<Name>QQ</Name>
</Configuration>
Try with this ... don't know what's happening with 'fh'. This assumes your data is in "gitissue2.dat".
package main import ( "bytes" "fmt" "github.com/clbanning/mxj" "io" "io/ioutil" ) func main() { b, err := ioutil.ReadFile("gitissue2.dat") if err != nil { fmt.Println("err:", err) return } r := bytes.NewReader(b) m := make(map[string]interface{}) for { v, err := mxj.NewMapXmlSeqReader(r) if err != nil { if err == io.EOF { break } if err != mxj.NoRoot { // handle error } } for key, val := range v { m[key] = val } } fmt.Printf("%v\n", m) }
It works, thanks a lot.
There was an issue - it has to do with how xml.NewDecoder treats *os.File as a reader. I added a work around to NewMapXmlReader() and NewMapXmlSeqReader() so that the original code I proposed will now work. Thanks for the use-case.
Updated and it works well. 👍
Try with this ... don't know what's happening with 'fh'. This assumes your data is in "gitissue2.dat".
package main
import (
"bytes"
"fmt"
"github.com/clbanning/mxj"
"io"
"io/ioutil"
)
func main() {
b, err := ioutil.ReadFile("gitissue2.dat")
if err != nil {
fmt.Println("err:", err)
return
}
r := bytes.NewReader(b)
m := make(map[string]interface{})
for {
v, err := mxj.NewMapXmlSeqReader(r)
if err != nil {
if err == io.EOF {
break
}
if err != mxj.NoRoot {
// handle error
}
}
for key, val := range v {
m[key] = val
}
}
fmt.Printf("%v\n", m)
}
But how can i convert it in xml again.
i am also not able to read xmlfile using NewMapXmlSeqReader(). gatting no root element error
To re-encode the MapSeq value(s) to XML try:
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"github.com/clbanning/mxj"
)
func main() {
b, err := ioutil.ReadFile("gitissue2.dat")
if err != nil {
fmt.Println("err:", err)
return
}
r := bytes.NewReader(b)
m := make(map[string]interface{})
for {
v, err := mxj.NewMapXmlSeqReader(r)
if err != nil {
if err == io.EOF {
break
}
if err != mxj.NoRoot {
// handle error
}
}
for key, val := range v {
m[key] = val
}
}
fmt.Printf("%v\n", m)
// re-encode as XML
newXML := []byte{}
for key, val := range m {
b, err := mxj.MapSeq(val.(map[string]interface{})).Xml(key)
if err != nil {
fmt.Println("err:", err)
return
}
newXML = append(newXML, b...)
}
fmt.Println(string(newXML))
}
Also, what is "xmlfile" you're referring to. Certainly not "gitissue2.dat."