123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- package util
- import (
- "encoding/json"
- "encoding/xml"
- "fmt"
- "io"
- )
- // Copyright 2021 Patrick Gundlach
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this software
- // and associated documentation files (the "Software"), to deal in the Software without restriction,
- // including without limitation the rights to use, copy, modify, merge, publish, distribute,
- // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- // The above copyright notice and this permission notice shall be included in all copies or
- // substantial portions of the Software.
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
- // AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
- // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- // encodeString encodes str as an element named entry with the attribute key="<value of key>" if key is not empty.
- func encodeString(enc *xml.Encoder, str string, key string) error {
- stringElt := xml.StartElement{Name: xml.Name{Local: "entry"}}
- var err error
- if key != "" {
- stringElt.Attr = []xml.Attr{{Name: xml.Name{Local: "key"}, Value: key}}
- }
- if err = enc.EncodeToken(stringElt); err != nil {
- return err
- }
- if err = enc.EncodeToken(xml.CharData([]byte(str))); err != nil {
- return err
- }
- return enc.EncodeToken(stringElt.End())
- }
- // ToXML reads the JSON file from jsonInput and writes to xmlOutput.
- func ToXML(jsonInput io.Reader, xmlOutput io.Writer) error {
- var err error
- dec := json.NewDecoder(jsonInput)
- enc := xml.NewEncoder(xmlOutput)
- root := xml.StartElement{}
- root.Name = xml.Name{Local: "Root"}
- mapElt := xml.StartElement{Name: xml.Name{Local: "map"}}
- aryElt := xml.StartElement{Name: xml.Name{Local: "array"}}
- // inMap is a stack with the last element shows if we are currently
- // in a map. This is to insert key=".." attributes.
- inMap := []bool{false}
- err = enc.EncodeToken(root)
- if err != nil {
- return err
- }
- var key string
- encodeLoop:
- for {
- tok, err := dec.Token()
- if err != nil && err != io.EOF {
- return err
- }
- if tok == nil {
- break encodeLoop
- }
- switch t := tok.(type) {
- case json.Delim:
- switch t {
- case '{':
- inMap = append(inMap, true)
- if key == "" {
- if enc.EncodeToken(mapElt); err != nil {
- return err
- }
- } else {
- attr := xml.Attr{Name: xml.Name{Local: "key"}, Value: key}
- se := mapElt.Copy()
- se.Attr = []xml.Attr{attr}
- if err = enc.EncodeToken(se); err != nil {
- return err
- }
- }
- key = ""
- case '[':
- inMap = append(inMap, false)
- if key == "" {
- if err = enc.EncodeToken(aryElt); err != nil {
- return err
- }
- } else {
- attr := xml.Attr{Name: xml.Name{Local: "key"}, Value: key}
- se := aryElt.Copy()
- se.Attr = []xml.Attr{attr}
- if err = enc.EncodeToken(se); err != nil {
- return err
- }
- }
- key = ""
- case ']':
- inMap = inMap[:len(inMap)-1]
- if key != "" {
- if err = encodeString(enc, key, ""); err != nil {
- return err
- }
- key = ""
- }
- if err = enc.EncodeToken(aryElt.End()); err != nil {
- return err
- }
- case '}':
- inMap = inMap[:len(inMap)-1]
- if key != "" {
- if err = encodeString(enc, key, ""); err != nil {
- return err
- }
- key = ""
- }
- if err = enc.EncodeToken(mapElt.End()); err != nil {
- return err
- }
- }
- case string:
- if inMap[len(inMap)-1] {
- if key != "" {
- if err = encodeString(enc, t, key); err != nil {
- return err
- }
- key = ""
- } else {
- key = t
- }
- } else {
- if err = encodeString(enc, t, ""); err != nil {
- return err
- }
- }
- case float64, bool:
- if err = encodeString(enc, fmt.Sprint(t), key); err != nil {
- return err
- }
- key = ""
- default:
- panic("not implemented")
- }
- }
- if err = enc.EncodeToken(root.End()); err != nil {
- return err
- }
- return enc.Flush()
- }
|