clbanning/mxj

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